2012-12-04 50 views
2

可能重複:
using dynamic IN clause in MSSQL在SQL Server中轉換失敗

我有一個SQL語句,其中包括參數,如@StartRow, @StartEnd, @CategoryIds

SELECT * FROM StackOverFlow 
WHERE 
StartRow = @StartRow 
AND StartEnd = @StartEnd 
AND CategoryId IN (@CategoryIds) 

當我設置像下面的參數:

DECLARE @StartRow INT = 1; 
DECLARE @StartRow INT = 10; 
DECLARE @CategoryId NVARCHAR(50); 
set @CategoryId ='124,125' 

失敗的消息是:爲nvarchar值 '124125' 轉換成數據 int類型時

轉換失敗。

當我手動設置WHERE語句像下面的SQL:

WHERE 
StartRow = @StartRow 
AND StartEnd = @StartEnd 
AND CategoryId IN (124, 125) 

它的工作原理。

我該如何解決轉換問題?

+1

你不能這樣做,你必須使用動態SQL。沒有時間寫出如何現在,但你可以查看它。同時查看動態SQl的陷阱。 – HLGEM

回答

3

爲此,您需要使用dynamic SQL。所以你會寫

DECLARE @StartRow INT = 1; 
DECLARE @StartRow INT = 10; 
DECLARE @CatogoryIds NVARCHAR(50); 
SET @CatogoryIds = N'124, 125'; 
DECLARE @SQL NVARCHAR(MAX); 
SET @SQL = N' 
    SELECT * 
    FROM StackOverFlow 
    WHERE 
     StartRow = ' + @StartRow + 
     N' AND StartEnd = ' + @StartEnd + 
     N' AND CategoryId IN (' + @CategoryIds + N');'; 
EXEC(@SQL); 
GO 

我希望這有助於。

2

如果使用動態SQL,你應該使用參數化查詢和sp_executesql的,像這樣

CREATE TABLE T (StartRow INT, StartEnd INT, CategoryID INT); 
INSERT T VALUES (1, 10, 124), (1, 10, 125), (1, 10, 126); 

DECLARE @StartRow INT = 1; 
DECLARE @StartEnd INT = 10; 
DECLARE @CategoryId NVARCHAR(50) ='124); DROP TABLE T; --'; 

DECLARE @SQL NVARCHAR(MAX); 
SET @SQL = N'SELECT * 
      FROM T 
      WHERE StartRow = @Start 
      AND  StartEnd = @End 
      AND  CategoryID IN (' + @CategoryId + ')' 

EXECUTE SP_EXECUTESQL @SQL, N'@Start INT, @End INT', @StartRow, @StartEnd; 

Dynamic SQL Example


可以使用SQL-Server的XML擴展做到這一點沒有動態SQL,雖然我我不確定你是否想要,你可能想要運行一些測試來檢查性能。

DECLARE @StartRow INT = 1; 
DECLARE @StartEnd INT = 10; 
DECLARE @CategoryId NVARCHAR(50) ='124,125'; 


DECLARE @X XML = CAST(N'<root><catid>' + REPLACE(@CategoryID, ',', '</catid><catid>') + '</catid></root>' AS XML); 

SELECT StartRow, 
     StartEnd, 
     CategoryID 
FROM T 
     INNER JOIN 
     ( SELECT [CatID] = cat.value('.', 'int') 
      FROM @X.nodes('/root/catid') c (cat) 
     ) c 
      ON c.CatID = CategoryID; 

Example using XML Extension

查詢基本轉換你的逗號delimted字符串轉換成XML,然後拆分XML到它自己的表。

這應該也會降低sql注入的風險,因爲任何格式錯誤的字符串都會拋出錯誤而不是運行。考慮到這些變量:

DECLARE @StartRow INT = 1; 
DECLARE @StartEnd INT = 10; 
DECLARE @CategoryId NVARCHAR(50) ='124,125); DROP TABLE T; --'; 

與XML擴展方法運行會給這個

Msg 245, Level 16, State 1, Line 13 
Conversion failed when converting the nvarchar value '124,125); DROP TABLE T; --' to data type int. 

SQL Injection Fail with XML Extensions

與動態SQL運行後會取得理想的結果,但下一次你來運行它你會得到:

Msg 208, Level 16, State 1, Line 1 
Invalid object name 'T'. 

SQL Injection Example

有分割字符串,而不是上面使用的XML方法,其他的方法,但它僅僅是演示動態SQL不是唯一的出路,如果你沒有你的輸入字符串的控制,然後不使用它會更明智,因爲惡意字符串會破壞您的數據!


對於您還可以使用表值參數答案的完整性的緣故。例如

CREATE TYPE dbo.IntegerList AS TABLE (value INT); 

CREATE PROCEDURE dbo.ExampleProcedure @StartRow INT, @StartEnd INT, @CategoryID dbo.IntegerList READONLY 
AS 
BEGIN 

    SELECT * 
    FROM T 
    WHERE StartRow = @StartRow 
    AND  StartEnd = @StartEnd 
    AND  CategoryID IN (SELECT Value FROM @CategoryID) 
END