因爲IN ('1,2,3')
與IN (1,2,3)
不同,所以您需要動態SQL或拆分功能。
拆分功能:
CREATE FUNCTION dbo.SplitInts
(
@List VARCHAR(MAX),
@Delimiter CHAR(1)
)
RETURNS TABLE
AS
RETURN (SELECT Item = CONVERT(INT, Item) FROM (
SELECT Item = x.i.value('(./text())[1]', 'int') FROM (
SELECT [XML] = CONVERT(XML, '<i>' + REPLACE(@List, @Delimiter, '</i><i>')
+ '</i>').query('.')) AS a CROSS APPLY [XML].nodes('i') AS x(i)) AS y
WHERE Item IS NOT NULL
);
代碼變成類似:
SELECT m.col1, m.col2 FROM dbo.model AS m
LEFT OUTER JOIN dbo.SplitInts(NULLIF(@brandids, ''), ',') AS br
ON m.brandid = COALESCE(br.Item, m.brandid)
LEFT OUTER JOIN dbo.SplitInts(NULLIF(@bodystyleid, ''), ',') AS bs
ON m.bodystyleid = COALESCE(bs.Item, m.bodystyleid)
WHERE (NULLIF(@brandids, '') IS NULL OR br.Item IS NOT NULL)
AND (NULLIF(@bodystyleid, '') IS NULL OR bs.Item IS NOT NULL);
(請注意,我加了很多NULLIF的處理在這裏......如果這些參數不具有價值,您應該傳遞NULL,而不是「空白」。)
動態SQL將導致由於參數嗅探導致計劃錯誤的機會少得多:
DECLARE @sql NVARCHAR(MAX);
SET @sql = N'SELECT columns FROM dbo.model
WHERE 1 = 1 '
+ COALESCE(' AND brandid IN (' + @brandids + ')', '')
+ COALESCE(' AND bodystyleid IN (' + @bodystyleid + ')', '');
EXEC sp_executesql @sql;
當然作爲@JamieCee中所指出的,動態的SQL 可能易受注射,如果搜索動態SQL的任何地方,你會發現。所以如果你不相信你的輸入,你會想要防範潛在的注入攻擊。就像您在應用程序代碼中組裝臨時SQL一樣。
當您遷移到SQL Server 2008或更高版本時,您應該查看table-valued parameters(example here)。
可以顯示調用存儲過程的代碼嗎?對於傳遞列表有一些技巧,你可以利用它從.NET語言中調用。 – JamieSee
嗨jamieSee,我正在使用實體框架4.0,所以我打電話給它在EF中調用SP的方式 – Paul