动态SQL查询给出类型错误

时间:2013-04-15 14:27:04

标签: sql sql-server sql-server-2008 tsql dynamic

我试图通过构建动态查询并存储在变量中并执行变量来编写一个简单的SP。

我目前收到以下错误:

  

Msg 206,Level 16,State 2,Line 16
  操作数类型冲突:datetime2与float

不兼容

以下代码:

DECLARE 
@table_Num
@1 varchar(100) = 'boo',
@2 int =2,
@3 varchar(100) ='default',
@4 varchar(50) = NULL,
@5 int =NULL,
@6 float =12,
@7 datetime2(0) ='1970-01-01 00:00:00',
@8 datetime2(0)='1970-01-01 00:00:00',
@9 varchar(50)='',
@10 varchar(50)=NULL,
@11 decimal(18,0)=0000000000000,
@12 int =999999

DECLARE @SQLString NVARCHAR(MAX)

SET @SQLString = 'INSERT INTO abc_'+@table_Num+'(col1, col2, col3, col4, col5, col6, col7, col8, col9, col10, col11, col12) 
VALUES ('+@1+',2,'+@3+','+@4+','+@5+','+@6+','+@7+','+@8+','+@9+','+@10+','+@11+','+@12+')'

EXEC (@SQLString)

据我所知,变量与表格类型的类型相同。有什么想法吗?

3 个答案:

答案 0 :(得分:3)

我猜这与你使用引号有关,但是很难遵循。我建议使用EXEC sp_executesql并将参数作为实际参数传递。对于这样的声明来说,这样做更容易一些,而且更加安全。

(根据TimLehner的评论编辑)

DECLARE @SQLString NVARCHAR(MAX), @ParamString NVARCHAR(MAX), @TableName sysname;
SET @TableName = N'abc_' + REPLACE(@table_num, '''', ''''''); --Escape apostrophes

IF OBJECT_ID(@TableName) IS NOT NULL
BEGIN
  SET @SQLString = 
    N'INSERT INTO ' + QUOTENAME(@TableName) +
    N' (col1, col2, col3, col4, col5, col6, col7, col8, col9, col10, col11, col12)
       VALUES (@1, @2, @3, @4, @5, @6, @7, @8, @9, @10, @11, @12)';
  SET @ParamString = N'@1 varchar(100), @2 int, @3 varchar(100), ... , @12 int)';

  EXEC sp_executesql @SQLString, @ParamString, @1, @2, @3, @4, @5, @6, @7, @8, @9, @10, @11, @12
END

Read about sp_execultesql on MSDN here

答案 1 :(得分:3)

要动态创建正确的insert语句,您至少需要:

  1. 将变量投射到字符串:cast(@2 as varchar(11))
  2. 字符串中的双撇号:replace(@1, '''', '''''')
  3. 在撇号中包裹字符串(包括日期作为字符串):'''' + replace(@1, '''', '''''') + ''''
  4. 处理空值,因为连接空值会产生null:coalesce(cast(@5 as varchar(11)), 'null')
  5. 这看起来不是很糟糕吗?

    正如其他人所说,这是运行动态SQL的最糟糕方式,并打开了一个名为 SQL Injection 的主要安全漏洞。如果这需要是动态的,请使用带有类型参数的sp_executesql(谢谢,@ JeffRosenberg)。但是,这个简单的插入也是一个简单的例子,根本不需要动态SQL(谢谢@AaronBertrand)。只需按原样运行命令:

    INSERT INTO table_1 (col1, col2, /* ... */ col12)
    VALUES (@1, @2, /* ... */ @12)
    

答案 2 :(得分:0)

您的字符串连接中存在转换问题。您需要将参数转换为varchar以构建字符串。

cast(@ 7 as varchar(50))。

FWIW,我认为您应该重新考虑如何构建查询。如果可能,请避免使用EXEC()。您将遇到此解决方案的各种问题。您可能还会遇到SQL注入问题。如果黑客设法发送int SQL代码,则可以重写您的插入查询。参数@ 1