web-dev-qa-db-ja.com

SQL Server-変数が宣言されたIn句

私が次のものを得たとしましょう:

DECLARE @ExcludedList VARCHAR(MAX)

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

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

エラー:varchar値 '、'をデータ型intに変換するときに変換に失敗しました。

エラーが発生する理由は理解していますが、解決方法がわかりません...

44
Melursus

次のような動的なspとしてこれを実行する必要があります

DECLARE @ExcludedList VARCHAR(MAX)

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

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

exec sp_executesql @sql
38
TonyP

これは、テーブル変数を使用してIN句の複数の値をリストする例です。明らかな理由は、長い手順で値のリストを1箇所のみ変更できることです。

さらに動的でユーザー入力を少なくするために、入力に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' )
34
Mikkel Tronsrud
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がオプションではなかったときに機能していました。

20
Carl Osterman

IN句で変数を使用することはできません- 動的SQL を使用するか、または 関数(TSQLまたはCLR)を使用して値のリストを変換する必要がありますテーブルに

動的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
5
OMG Ponies

最初に、次のように、値の区切りリストをテーブルに分割するクイック関数を作成します。

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

これは私たちのプロジェクトで本当にうまくいきました...

もちろん、もしそうであれば、あなたの質問ではありませんが、反対も行うことができます。

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

これは、オプションの複数選択パラメーターリストを持つレポートを処理する際に非常に便利です。パラメーターがNULLの場合、すべての値を選択する必要がありますが、1つ以上の値がある場合は、それらの値でレポートデータをフィルター処理します。次に、次のようにSQLを使用します。

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

このように、@ ExcludeListがNULL値の場合、結合のOR句は、この値のフィルタリングをオフにするスイッチになります。非常に便利です...

5
laughsloudly

問題があると思う

3 + ', ' + 4

に変更する

'3' + ', ' + '4'

DECLARE @ExcludedList VARCHAR(MAX)

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

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

クエリが次のようになるように@ExcludedListeを設定します

いずれか

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

または

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

動的クエリなしでそれを行う別のソリューションがあります。同様にxqueryを使用して行うことができます。

    SET @Xml = cast(('<A>'+replace('3,4,22,6014',',' ,'</A><A>')+'</A>') AS XML)
    Select @Xml

    SELECT A.value('.', 'varchar(max)') as [Column] FROM @Xml.nodes('A') AS FN(A)

完全なソリューションは次のとおりです: http://raresql.com/2011/12/21/how-to-use-multiple-values-for-in-clause-using-same-parameter -sql-server /

1
user1059637

これを試して:

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
Makis