2010-05-31 289 views
30

Let子句說我有以下幾點:SQL服務器 - 與聲明的變量

DECLARE @ExcludedList VARCHAR(MAX) 

SET @ExcludedList = 3 + ', ' + 4 + ' ,' + '22' 

SELECT * FROM A WHERE Id NOT IN (@ExcludedList) 

錯誤:轉換爲varchar值「」 int數據類型時,轉換失敗。

我理解爲什麼錯誤是有,但我不知道如何解決它...

+0

@TomTom等 - 我不同意,這是一個重複。另一個問題涵蓋了更多與這個問題在具體問題中涉及的內容無關的問題。最重要的是,我很高興我找到了這篇文章,而不是其他文章 - 因爲這個問題恰恰解決了我的問題。 – condiosluzverde 2018-02-27 18:47:04

回答

30

您需要執行這個作爲一個動態的SP一樣

DECLARE @ExcludedList VARCHAR(MAX) 

SET @ExcludedList = '3,4,22,6014' 
declare @sql nvarchar(Max) 

Set @sql='SELECT * FROM [A] WHERE Id NOT IN ('[email protected]+')' 

exec sp_executesql @sql 
+7

如果ExcludedList是由用戶輸入的話,是不是容易受到SQL注入的影響?例如,ExcludedList ='3); DROP TABLE USERS; - '(評論系統不會讓我用(at)號) – ristonj 2012-04-20 20:24:51

+0

沒關係。多個變量(每個項目一個)或動態SQL是處理這個問題的唯一方法。是的,你必須小心。或者刪除in子句(並將這些項目加載到臨時表/表變量中,然後加入)。 – TomTom 2014-12-11 12:51:45

+0

我寧願使用字符串分隔符而不是動態sql來避免sql注入。 http://sqlperformance.com/2012/07/t-sql-queries/split-strings – 2016-09-01 16:37:12

0

我認爲問題出在

3 + ', ' + 4 

改變它

'3' + ', ' + '4' 

DECLARE @ExcludedList VARCHAR(MAX) 

SET @ExcludedList = '3' + ', ' + '4' + ' ,' + '22' 

SELECT * FROM A WHERE Id NOT IN (@ExcludedList) 

SET @ExcludedListe,使您的查詢應該變爲

或者

SELECT * FROM A WHERE Id NOT IN ('3', '4', '22') 

SELECT * FROM A WHERE Id NOT IN (3, 4, 22) 
+1

修復了set語句,但select查詢仍然不起作用 – 2010-05-31 15:38:03

+0

這對我來說非常有用 – 2016-01-21 11:56:50

0

試試這個:

CREATE PROCEDURE MyProc @excludedlist integer_list_tbltype READONLY AS 
    SELECT * FROM A WHERE ID NOT IN (@excludedlist) 

然後調用它像這樣:

DECLARE @ExcludedList integer_list_tbltype 
INSERT @ExcludedList(n) VALUES(3, 4, 22) 
exec MyProc @ExcludedList 
1

不能在使用變量一個IN子句 - 您需要使用dynamic SQL或使用a function (TSQL or CLR) to convert the list of values into a table

動態SQL例如:

DECLARE @ExcludedList VARCHAR(MAX) 
    SET @ExcludedList = 3 + ',' + 4 + ',' + '22' 

DECLARE @SQL NVARCHAR(4000) 
    SET @SQL = 'SELECT * FROM A WHERE Id NOT IN (@ExcludedList) ' 

BEGIN 

    EXEC sp_executesql @SQL '@ExcludedList VARCHAR(MAX)' @ExcludedList 

END 
16
DECLARE @IDQuery VARCHAR(MAX) 
SET @IDQuery = 'SELECT ID FROM SomeTable WHERE Condition=Something' 
DECLARE @ExcludedList TABLE(ID VARCHAR(MAX)) 
INSERT INTO @ExcludedList EXEC(@IDQuery)  
SELECT * FROM A WHERE Id NOT IN (@ExcludedList) 

我知道我回應舊的文章,但我想分享當想避免使用動態SQL時如何使用變量表的示例。我不確定它是否是最有效的方式,但是當動態SQL不是一個選項時,這對我來說是過去的工作。

+3

我喜歡這個,因爲你避免使用動態SQL – MattK311 2014-11-25 13:22:39

3

首先,創建一個快捷功能,將值的分隔列表分裂成一個表,像這樣:

CREATE FUNCTION dbo.udf_SplitVariable 
(
    @List varchar(8000), 
    @SplitOn varchar(5) = ',' 
) 

RETURNS @RtnValue TABLE 
(
    Id INT IDENTITY(1,1), 
    Value VARCHAR(8000) 
) 

AS 
BEGIN 

--Account for ticks 
SET @List = (REPLACE(@List, '''', '')) 

--Account for 'emptynull' 
IF LTRIM(RTRIM(@List)) = 'emptynull' 
BEGIN 
    SET @List = '' 
END 

--Loop through all of the items in the string and add records for each item 
WHILE (CHARINDEX(@SplitOn,@List)>0) 
BEGIN 

    INSERT INTO @RtnValue (value) 
    SELECT Value = LTRIM(RTRIM(SUBSTRING(@List, 1, CHARINDEX(@SplitOn, @List)-1))) 

    SET @List = SUBSTRING(@List, CHARINDEX(@SplitOn,@List) + LEN(@SplitOn), LEN(@List)) 

END 

INSERT INTO @RtnValue (Value) 
SELECT Value = LTRIM(RTRIM(@List)) 

RETURN 

END 

然後調用功能如此...

SELECT * 
FROM A 
LEFT OUTER JOIN udf_SplitVariable(@ExcludedList, ',') f ON A.Id = f.Value 
WHERE f.Id IS NULL 

This h在我們的項目中工作得很好...

當然,如果情況如此(也不是你的問題),也可以做相反的事情。

SELECT * 
FROM A 
INNER JOIN udf_SplitVariable(@ExcludedList, ',') f ON A.Id = f.Value 

當處理具有可選多選參數列表的報表時,這真的很方便。如果參數爲NULL,則需要選擇所有值,但是如果它具有一個或多個值,則需要按這些值篩選報告數據。然後使用SQL這樣的:

SELECT * 
FROM A 
INNER JOIN udf_SplitVariable(@ExcludedList, ',') f ON A.Id = f.Value OR @ExcludeList IS NULL 

這樣,如果@ExcludeList是NULL值,or子句的加入變成關閉該值濾波開關。非常方便...

21

這是一個例子,我使用表變量在IN子句中列出多個 值。顯而易見的原因是能夠在長程序中將值列表更改爲只有一個地方。

爲了使其更加動態和alowing用戶輸入,我建議 聲明一個varchar變量的輸入,然後使用WHILE到 環槽在可變的數據並將其插入到表 變量。

將@your_list,Your_table和值替換爲真正的東西。

DECLARE @your_list TABLE (list varchar(25)) 
INSERT into @your_list 
VALUES ('value1'),('value2376') 

SELECT * 
FROM your_table 
WHERE your_column in (select list from @your_list) 

select語句abowe會做一樣的:

SELECT * 
FROM your_table 
WHERE your_column in ('value','value2376') 
+0

這會導致性能下降,因爲第二個選擇在子句中,因爲它將被執行的每一行 – fatiDev 2017-12-12 11:15:41