ODBC SQL 服务器驱动程序 - 在 recordset.UpdateBatch 方法上“44444”错误附近的语法不正确
ODBC SQL Server Driver - Incorrect syntax near '44444' error - on recordset.UpdateBatch method
VB.Net windows 表单程序在 "production" 环境中正常运行(即 .EXE 在 Windows 2008R2 服务器上运行,连接到 SQL另一台服务器上的 Server 2008 数据库)。
该平台被克隆到 "test" 环境(即托管在 AWS 上;数据库服务器已由管理过渡到 SQL Server 2016 的系统管理员升级到AWS).
问题:在 AWS 上测试的这个错误是否指向某种类型的 SQL 2016 配置问题?
代码片段如下:
Dim cn As New ADODB.Connection()
cn.ConnectionString = BuildConnectStringODBC()
cn.Open()
rs = New Recordset
rs.CursorLocation = ADODB.CursorLocationEnum.adUseClient
rs.CursorType = ADODB.CursorTypeEnum.adOpenKeyset
rs.LockType = ADODB.LockTypeEnum.adLockBatchOptimistic
rs.Open("ImportTempTable", cn)
rs.AddNew()
rs.Fields("StateCD").Value = CRMortgage.StateCD
rs.Fields("CountyCD").Value = CRMortgage.CountyCD
' etc.
rs.UpdateBatch()
单步调试表明,在 rs 对象上的所有上述方法都可以正常工作,直到 rs.UpdateBatch 失败并出现 "incorrect syntax" 错误。
这个程序在 "production" 和系统管理员中多次执行没有问题,我怀疑 SQL 服务器配置或选项有问题,但我们不确定从哪里开始。
编辑更新:
这是来自 SQL Mgmt Studio 的 ImportTempTable 的脚本模式:
CREATE TABLE [dbo].[ImportTempTable](
[StateCD] [varchar](2) NULL,
[CountyCD] [varchar](3) NULL,
[SaleMnYear] [datetime] NULL,
[LenderName] [varchar](40) NULL,
[MDSID] [varchar](6) NULL,
[Amt_PUR] [int] NULL,
[Nbr_MTG] [int] NULL,
[Amt_MTG] [int] NULL,
[Nbr_JUMBO] [int] NULL,
[Amt_JUMBO] [int] NULL,
[Nbr_GOVT] [int] NULL,
[Amt_GOVT] [int] NULL,
[Nbr_Fixed] [int] NULL,
[Nbr_ARMS] [int] NULL,
[Nbr_NewConst] [int] NULL,
[Amt_Fixed] [int] NULL,
[Amt_ARMS] [int] NULL,
[Amt_NewConst] [int] NULL,
[LTV] [real] NULL,
[Nbr_Below80] [int] NULL,
[Nbr_80_85] [int] NULL,
[Nbr_85_90] [int] NULL,
[Nbr_Above90] [int] NULL,
[LoanType] [varchar](1) NULL,
[SaleType] [varchar](1) NULL,
[RateType] [varchar](1) NULL,
[CondoCode] [varchar](1) NULL,
[Zip] [varchar](5) NULL,
[ZipSuffix] [varchar](4) NULL,
[StateAbbr] [varchar](2) NULL,
[DateImported] [datetime] NULL,
[RecordType] [varchar](1) NULL
) ON [PRIMARY]
经过调查,我确实发现了两个与上述相关的触发器table:
ALTER TRIGGER [dbo].[ImportTempTable_ITrig] ON [dbo].[ImportTempTable] FOR INSERT AS
/*
* PREVENT NULL VALUES IN 'SaleMnYear'
*/
IF (SELECT Count(*) FROM inserted WHERE SaleMnYear IS NULL) > 0
BEGIN
RAISERROR 44444 'Field ''SaleMnYear'' cannot contain a null value.'
ROLLBACK TRANSACTION
END
ELSE
/*
* PREVENT NULL VALUES IN 'LenderName'
*/
IF (SELECT Count(*) FROM inserted WHERE LenderName IS NULL) > 0
BEGIN
RAISERROR 44444 'Field ''LenderName'' cannot contain a null value.'
ROLLBACK TRANSACTION
END
和
ALTER TRIGGER [dbo].[ImportTempTable_UTrig] ON [dbo].[ImportTempTable] FOR UPDATE AS
/*
* PREVENT NULL VALUES IN 'SaleMnYear'
*/
IF (SELECT Count(*) FROM inserted WHERE SaleMnYear IS NULL) > 0
BEGIN
RAISERROR 44444 'Field ''SaleMnYear'' cannot contain a null value.'
ROLLBACK TRANSACTION
END
ELSE
/*
* PREVENT NULL VALUES IN 'LenderName'
*/
IF (SELECT Count(*) FROM inserted WHERE LenderName IS NULL) > 0
BEGIN
RAISERROR 44444 'Field ''LenderName'' cannot contain a null value.'
ROLLBACK TRANSACTION
END
我不知道这些触发器已经到位。我会重新思考他们存在的理由。也许这是多年来我们第一次得到 "bad data" 并因此引发了这个愚蠢的错误。我认为上面列定义的 NULL 属性将允许 NULL;这种触发方法似乎是不明智的。
SQL 中的实例级别是否有可以启用或禁用触发器的东西?我觉得不是...
更多的研究应该可以解决这个问题。
Incorrect syntax near '44444'
错误表示 SQL 触发器使用未记录的 RAISERROR
语法版本,最高支持 SQL Server 2008 R2。从 SQL Server 2012 开始已经不支持未记录的 RAISERROR
语法,因此您需要使用支持的 RAISERROR
syntax or use THROW
作为替代:
-- RAISERROR example
RAISERROR(44444, -1, -1, 'Field ''SaleMnYear'' cannot contain a null value.');
-- THROW example
THROW 44444, 'Field ''SaleMnYear'' cannot contain a null value.', 1;
此外,您可以尝试从 ImportTempTable
中删除 ImportTempTable_ITrig
和 ImportTempTable_UTrig
触发器,然后将列 SaleMnYear
和 LenderName
设置为不可空数据类型,从较新的 SQL 服务器版本开始,不需要触发器来检查空值。
DROP TRIGGER IF EXISTS [dbo].[ImportTempTable_ITrig]
DROP TRIGGER IF EXISTS [dbo].[ImportTempTable_UTrig]
-- if the table already contains null value, update them first
UPDATE [dbo].[ImportTempTable] SET SaleMnYear = {value}, LenderName = {value}
WHERE SaleMnYear IS NULL {AND/OR} LenderName IS NULL
ALTER TABLE [dbo].[ImportTempTable] ALTER COLUMN SaleMnYear {data_type} NOT NULL
ALTER TABLE [dbo].[ImportTempTable] ALTER COLUMN LenderName {data_type} NOT NULL
截至 RecordSet.UpdateBatch
因上述错误而停止,它假设 运行 ADO 更新进程试图将空值添加到 SaleMnYear
或 LenderName
通过 if-condition 触发器设置为不允许空值的列(确保源数据列中的记录不包含空值)。
注意:我建议使用托管的 SqlClient.SqlConnection
而不是 ODBC 的 ADODB.Connection
来处理 SQL 服务器连接实例。
参考:
Differences between RAISERROR and THROW in SQL Server
类似问题:
Migrating from SQL Server 2008r2 to SQL Sever 2012
RAISERROR issue since migration to SQL Server 2012
VB.Net windows 表单程序在 "production" 环境中正常运行(即 .EXE 在 Windows 2008R2 服务器上运行,连接到 SQL另一台服务器上的 Server 2008 数据库)。
该平台被克隆到 "test" 环境(即托管在 AWS 上;数据库服务器已由管理过渡到 SQL Server 2016 的系统管理员升级到AWS).
问题:在 AWS 上测试的这个错误是否指向某种类型的 SQL 2016 配置问题?
代码片段如下:
Dim cn As New ADODB.Connection()
cn.ConnectionString = BuildConnectStringODBC()
cn.Open()
rs = New Recordset
rs.CursorLocation = ADODB.CursorLocationEnum.adUseClient
rs.CursorType = ADODB.CursorTypeEnum.adOpenKeyset
rs.LockType = ADODB.LockTypeEnum.adLockBatchOptimistic
rs.Open("ImportTempTable", cn)
rs.AddNew()
rs.Fields("StateCD").Value = CRMortgage.StateCD
rs.Fields("CountyCD").Value = CRMortgage.CountyCD
' etc.
rs.UpdateBatch()
单步调试表明,在 rs 对象上的所有上述方法都可以正常工作,直到 rs.UpdateBatch 失败并出现 "incorrect syntax" 错误。
这个程序在 "production" 和系统管理员中多次执行没有问题,我怀疑 SQL 服务器配置或选项有问题,但我们不确定从哪里开始。
编辑更新:
这是来自 SQL Mgmt Studio 的 ImportTempTable 的脚本模式:
CREATE TABLE [dbo].[ImportTempTable](
[StateCD] [varchar](2) NULL,
[CountyCD] [varchar](3) NULL,
[SaleMnYear] [datetime] NULL,
[LenderName] [varchar](40) NULL,
[MDSID] [varchar](6) NULL,
[Amt_PUR] [int] NULL,
[Nbr_MTG] [int] NULL,
[Amt_MTG] [int] NULL,
[Nbr_JUMBO] [int] NULL,
[Amt_JUMBO] [int] NULL,
[Nbr_GOVT] [int] NULL,
[Amt_GOVT] [int] NULL,
[Nbr_Fixed] [int] NULL,
[Nbr_ARMS] [int] NULL,
[Nbr_NewConst] [int] NULL,
[Amt_Fixed] [int] NULL,
[Amt_ARMS] [int] NULL,
[Amt_NewConst] [int] NULL,
[LTV] [real] NULL,
[Nbr_Below80] [int] NULL,
[Nbr_80_85] [int] NULL,
[Nbr_85_90] [int] NULL,
[Nbr_Above90] [int] NULL,
[LoanType] [varchar](1) NULL,
[SaleType] [varchar](1) NULL,
[RateType] [varchar](1) NULL,
[CondoCode] [varchar](1) NULL,
[Zip] [varchar](5) NULL,
[ZipSuffix] [varchar](4) NULL,
[StateAbbr] [varchar](2) NULL,
[DateImported] [datetime] NULL,
[RecordType] [varchar](1) NULL
) ON [PRIMARY]
经过调查,我确实发现了两个与上述相关的触发器table:
ALTER TRIGGER [dbo].[ImportTempTable_ITrig] ON [dbo].[ImportTempTable] FOR INSERT AS
/*
* PREVENT NULL VALUES IN 'SaleMnYear'
*/
IF (SELECT Count(*) FROM inserted WHERE SaleMnYear IS NULL) > 0
BEGIN
RAISERROR 44444 'Field ''SaleMnYear'' cannot contain a null value.'
ROLLBACK TRANSACTION
END
ELSE
/*
* PREVENT NULL VALUES IN 'LenderName'
*/
IF (SELECT Count(*) FROM inserted WHERE LenderName IS NULL) > 0
BEGIN
RAISERROR 44444 'Field ''LenderName'' cannot contain a null value.'
ROLLBACK TRANSACTION
END
和
ALTER TRIGGER [dbo].[ImportTempTable_UTrig] ON [dbo].[ImportTempTable] FOR UPDATE AS
/*
* PREVENT NULL VALUES IN 'SaleMnYear'
*/
IF (SELECT Count(*) FROM inserted WHERE SaleMnYear IS NULL) > 0
BEGIN
RAISERROR 44444 'Field ''SaleMnYear'' cannot contain a null value.'
ROLLBACK TRANSACTION
END
ELSE
/*
* PREVENT NULL VALUES IN 'LenderName'
*/
IF (SELECT Count(*) FROM inserted WHERE LenderName IS NULL) > 0
BEGIN
RAISERROR 44444 'Field ''LenderName'' cannot contain a null value.'
ROLLBACK TRANSACTION
END
我不知道这些触发器已经到位。我会重新思考他们存在的理由。也许这是多年来我们第一次得到 "bad data" 并因此引发了这个愚蠢的错误。我认为上面列定义的 NULL 属性将允许 NULL;这种触发方法似乎是不明智的。
SQL 中的实例级别是否有可以启用或禁用触发器的东西?我觉得不是...
更多的研究应该可以解决这个问题。
Incorrect syntax near '44444'
错误表示 SQL 触发器使用未记录的 RAISERROR
语法版本,最高支持 SQL Server 2008 R2。从 SQL Server 2012 开始已经不支持未记录的 RAISERROR
语法,因此您需要使用支持的 RAISERROR
syntax or use THROW
作为替代:
-- RAISERROR example
RAISERROR(44444, -1, -1, 'Field ''SaleMnYear'' cannot contain a null value.');
-- THROW example
THROW 44444, 'Field ''SaleMnYear'' cannot contain a null value.', 1;
此外,您可以尝试从 ImportTempTable
中删除 ImportTempTable_ITrig
和 ImportTempTable_UTrig
触发器,然后将列 SaleMnYear
和 LenderName
设置为不可空数据类型,从较新的 SQL 服务器版本开始,不需要触发器来检查空值。
DROP TRIGGER IF EXISTS [dbo].[ImportTempTable_ITrig]
DROP TRIGGER IF EXISTS [dbo].[ImportTempTable_UTrig]
-- if the table already contains null value, update them first
UPDATE [dbo].[ImportTempTable] SET SaleMnYear = {value}, LenderName = {value}
WHERE SaleMnYear IS NULL {AND/OR} LenderName IS NULL
ALTER TABLE [dbo].[ImportTempTable] ALTER COLUMN SaleMnYear {data_type} NOT NULL
ALTER TABLE [dbo].[ImportTempTable] ALTER COLUMN LenderName {data_type} NOT NULL
截至 RecordSet.UpdateBatch
因上述错误而停止,它假设 运行 ADO 更新进程试图将空值添加到 SaleMnYear
或 LenderName
通过 if-condition 触发器设置为不允许空值的列(确保源数据列中的记录不包含空值)。
注意:我建议使用托管的 SqlClient.SqlConnection
而不是 ODBC 的 ADODB.Connection
来处理 SQL 服务器连接实例。
参考:
Differences between RAISERROR and THROW in SQL Server
类似问题:
Migrating from SQL Server 2008r2 to SQL Sever 2012
RAISERROR issue since migration to SQL Server 2012