在 SQL INSERT CASE 查询中将 int 转换为日期时转换失败

Conversion failure converting int to date within an SQL INSERT CASE query

提问人:Almo 提问时间:7/27/2023 最后编辑:Almo 更新时间:7/31/2023 访问量:74

问:

我在这里阅读了许多文章(例如,在 CASE 语句中使用 CAST 时的数据转换错误),这些文章讨论了数据类型优先级是我今天一直在努力解决的问题的原因,但我认为我的是不同的。我的一台开发计算机正在运行 SQL Server,并创建了一个运行兼容级别 110 的数据库。我创建了一个表格:-

CREATE TABLE [dbo].[SyncDataRecords](
    [ID] [int] IDENTITY(1,1) NOT NULL,
    [SyncDataID] [int] NOT NULL,
    [FldVar] [sql_variant] NULL,
 CONSTRAINT [PK_SyncRecords_1] PRIMARY KEY CLUSTERED 
(
    [ID] ASC
)WITH (STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]

我还有另一个表格,其中列出了我的应用程序中涉及的字段:-

CREATE TABLE [dbo].[SyncDataFields](
    [ID] [int] IDENTITY(1,1) NOT NULL,
    [SyncDataID] [int] NOT NULL,
    [FldName] [nvarchar](128) NOT NULL,
    [FldBaseType] [nvarchar](32) NOT NULL,
    [PK] [bit] NOT NULL,
 CONSTRAINT [PK_SyncDataFields] PRIMARY KEY CLUSTERED 
(
    [ID] ASC
)WITH (STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]

针对此数据库,我可以通过 SqlClient.SqlCommand 参数化命令从应用程序中成功执行以下查询:-

DECLARE @FldTyp NVARCHAR(16);

SELECT @FldTyp = UPPER(FldBaseType)
FROM   SyncDataFields
WHERE  SyncDataID = @SyncDataID
       AND PK = 1;

INSERT INTO SyncDataRecords
            (SyncDataID,
             FldVar)
VALUES      (@SyncDataID,
             CASE
               WHEN @FldTyp = 'SQL_VARIANT' THEN CAST(@FldVar AS SQL_VARIANT)
               WHEN @FldTyp = 'NVARCHAR' THEN CAST(@FldVar AS NVARCHAR(4000))
               WHEN @FldTyp = 'BIGINT' THEN CAST(@FldVar AS BIGINT)
               WHEN @FldTyp = 'BIT' THEN CAST(@FldVar AS BIT)
               WHEN @FldTyp = 'DECIMAL' THEN CAST(@FldVar AS DECIMAL)
               WHEN @FldTyp = 'INT' THEN CAST(@FldVar AS INT)
               WHEN @FldTyp = 'MONEY' THEN CAST(@FldVar AS MONEY)
               WHEN @FldTyp = 'NUMERIC' THEN CAST(@FldVar AS NUMERIC)
               WHEN @FldTyp = 'SMALLINT' THEN CAST(@FldVar AS SMALLINT)
               WHEN @FldTyp = 'SMALLMONEY' THEN CAST(@FldVar AS SMALLMONEY)
               WHEN @FldTyp = 'TINYINT' THEN CAST(@FldVar AS TINYINT)
               WHEN @FldTyp = 'FLOAT' THEN CAST(@FldVar AS FLOAT)
               WHEN @FldTyp = 'REAL' THEN CAST(@FldVar AS REAL)
               WHEN @FldTyp = 'DATE' THEN CAST(@FldVar AS DATE)
               WHEN @FldTyp = 'DATETIME' THEN CAST(@FldVar AS DATETIME)
               WHEN @FldTyp = 'SMALLDATETIME' THEN CAST(@FldVar AS SMALLDATETIME)
               WHEN @FldTyp = 'TIME' THEN CAST(@FldVar AS TIME)
               WHEN @FldTyp = 'CHAR' THEN CAST(@FldVar AS CHAR)
               WHEN @FldTyp = 'VARCHAR' THEN CAST(@FldVar AS VARCHAR(4000))
               WHEN @FldTyp = 'NCHAR' THEN CAST(@FldVar AS NCHAR)
               WHEN @FldTyp = 'VARBINARY' THEN CAST(@FldVar AS VARBINARY)
               ELSE CAST(@FldVar AS SQL_VARIANT)
             END);

SELECT @@IDENTITY; 

作为测试,我将 @SyncDataID 设置为 1(整数),将 @FldVar设置为 1234(整数),这导致@FldTyp为“INT”。然后,我创建了一个使用 Azure 托管的重复数据库和表,默认为兼容级别 150。我可以通过 SSMS 成功执行相同的查询,并根据需要声明其他变量。但是,如果我将应用程序连接到 Azure 托管的 SQL 数据库,则会引发错误

不允许从数据类型 int 到 date 的显式转换

使应用程序成功的唯一方法是将 Azure SQL 数据库的兼容级别降低到 110,以匹配我的开发级别。即使将 CASE 更改为 IF ELSE IF 也无济于事,我仍然收到完全相同的错误。

我使用的触发错误的代码是这样的:

objInsPKCommand.CommandText = "DECLARE @FldTyp nvarchar(16);SELECT @FldTyp=UPPER(FldBaseType) FROM SyncDataFields WHERE SyncDataID=@SyncDataID AND PK=1;INSERT INTO SyncDataRecords (SyncDataID, FldVar) VALUES (@SyncDataID, CASE WHEN @FldTyp='SQL_VARIANT' THEN CAST(@FldVar AS sql_variant) WHEN @FldTyp='NVARCHAR' THEN CAST(@FldVar AS NVARCHAR(4000)) WHEN @FldTyp='BIGINT' THEN CAST(@FldVar AS BigInt) WHEN @FldTyp='BIT' THEN CAST(@FldVar AS Bit) WHEN @FldTyp='DECIMAL' THEN CAST(@FldVar AS decimal) WHEN @FldTyp='INT' THEN CAST(@FldVar AS Int) WHEN @FldTyp='MONEY' THEN CAST(@FldVar AS Money) WHEN @FldTyp='NUMERIC' THEN CAST(@FldVar AS Numeric) WHEN @FldTyp='SMALLINT' THEN CAST(@FldVar AS SmallInt) WHEN @FldTyp='SMALLMONEY' THEN CAST(@FldVar AS SMALLMONEY) WHEN @FldTyp='TINYINT' THEN CAST(@FldVar AS tinyint) WHEN @FldTyp='FLOAT' THEN CAST(@FldVar AS float) WHEN @FldTyp='REAL' THEN CAST(@FldVar AS Real) WHEN @FldTyp='DATE' THEN CAST(@FldVar AS Date) WHEN @FldTyp='DATETIME' THEN CAST(@FldVar AS DateTime) WHEN @FldTyp='SMALLDATETIME' THEN CAST(@FldVar AS SmallDateTime) WHEN @FldTyp='TIME' THEN CAST(@FldVar AS Time) WHEN @FldTyp='CHAR' THEN CAST(@FldVar AS char) WHEN @FldTyp='VARCHAR' THEN CAST(@FldVar AS VarChar(4000)) WHEN @FldTyp='NCHAR' THEN CAST(@FldVar AS NChar) WHEN @FldTyp='VARBINARY' THEN CAST(@FldVar AS varbinary) ELSE CAST(@FldVar AS sql_variant) END);SELECT @@IDENTITY;"
objInsPKCommand.Parameters.Add("SyncDataID", SqlDbType.Int)
objInsPKCommand.Parameters.Add("FldVar", SqlDbType.Variant)
objInsPKCommand.Parameters.Item("SyncDataID").Value = 1
objInsPKCommand.Parameters.Item("FldVar").Value = 1234
intPKID = objInsPKCommand.ExecuteScalar

请有人能够为我指出解释何时发生更改的方向,以及我可能需要如何更改我的查询命令,以便它继续在兼容级别 150 下工作。提前非常感谢。

相关记录的 SyncDataFields 表示例:-

编号 SyncDataID FldName(英语:FldName) FldBaseType PK型
70 19 编号 整数 1
71 19 名字 NVarChar 0
72 19 样式代码 NVarChar 0
73 19 批发GBP 十进制 0
101 19 品牌 NVarChar 0
C# ado.net azure-sql-database sqlclient

评论

1赞 Martin Smith 7/27/2023
确切的错误消息文本是什么?此外,如果无法在 SSMS 中重现此内容,并且只有应用程序代码才能获取它,则会是什么样子?还有旁注,但像没有长度这样的事情是非常可疑的。参数的数据类型是什么?CAST(@FldVar AS NCHAR)@FldVar
0赞 marc_s 7/27/2023
我建议使用 SCOPE_IDENTITY() 而不是其他任何东西(如 )来获取新插入的标识值。有关原因的解释,请参阅此博客文章@@IDENTITY+
3赞 Martin Smith 7/27/2023
我没有做过太多工作,但按照你的编辑......假设参数是类型,而列是类型,为什么需要它?你不能把参数插入到列中吗?SQL_VARIANTSqlDbType.VariantSQL_VARIANTCASE
0赞 Charlieface 7/27/2023
表中实际有哪些数据?我同意你似乎根本不需要整体,除了字符串类型。SyncDataFieldsCASE
0赞 Almo 7/27/2023
我包含了 CASE 语句,因为我开始遇到这样的问题,即从 JSON 响应填充的 @FldVar 的值将看起来像数字的文本误认为是数字(或者相反,这是一段时间前的事了!但是从你所说的来看,只要我小心字符串,我就不需要打扰 CASTing 其他数据类型?我仍然想知道为什么我现有的命令针对版本 110 而不是 150 版本数据库运行。

答: 暂无答案