2013-04-15 53 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