2013-04-15 27 views
1

我想通过构建动态查询并存储在变量中并执行变量来编写简单的SP。动态SQL查询给出类型错误

我目前得到以下错误:

Msg 206, Level 16, State 2, Line 16
Operand type clash: datetime2 is incompatible with 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_'[email protected]_Num+'(col1, col2, col3, col4, col5, col6, col7, col8, col9, col10, col11, col12) 
VALUES ('[email protected]+',2,'[email protected]+','[email protected]+','[email protected]+','[email protected]+','[email protected]+','[email protected]+','[email protected]+','[email protected]+','[email protected]+','[email protected]+')' 

EXEC (@SQLString) 

至于我能看到的变量是同一类型的表山坳类型。有任何想法吗?

+0

您是否还可以包含'table_1'的定义? –

+2

这是构建动态SQL字符串的绝对最糟糕的方法。你能解释为什么它首先需要成为动态SQL吗? –

+0

@AaronBertrand伟大的一点。我认为这是理所当然的,因为它是动态SQL。 –

回答

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

+1 ['' sp_executesql'绝对是执行动态SQL的方式](http://sqlblog.com/blogs/aaron_bertrand/archive/2011/09/17/bad-habits-to-kick-using-exec-instead-of-sp- executionql.aspx),特别是当大多数参数可以被强制输入时(将它们作为一个大字符串一起滚动)。 –

+0

@AaronBertrand感谢您的编辑。你是对的,parens是一个错误。 –

+0

谢谢你们,我会在几个小时内检查你的解决方案 – Fearghal

0

您在字符串连接中有投射问题。你需要将你的参数转换成varchar来构建你的字符串。

cast(@ 7 as varchar(50))。

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

+0

谢谢,我尝试了varchar方法,认为我遇到了另一个问题,但我再次检查出来。 – Fearghal

2

要建立正确的插入语句动态,你必须,至少是:

  1. 演员变量字符串:cast(@2 as varchar(11))
  2. 双引号中的字符串:replace(@1, '''', '''''')
  3. 总结字符串(包括日期作为字符串)在撇号中:'''' + replace(@1, '''', '''''') + ''''
  4. 处理空值,因为连接null会产生null:coalesce(cast(@5 as varchar(11)), 'null')

这难道不是看可怕

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

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

嗨,大家好,对不起,我meade在我的例子中的一个错误,它prob不会做太多的差异,但继承人的差异....我想能够说明tabel名称被插入到dymamically,我已经改变了原来的问题代码于是 – Fearghal