web-dev-qa-db-fra.com

SQL Server - Clause In avec une variable déclarée

Disons que j'ai ce qui suit:

DECLARE @ExcludedList VARCHAR(MAX)

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

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

Erreur: la conversion a échoué lors de la conversion de la valeur varchar ',' en type de données int.

Je comprends pourquoi l'erreur est là mais je ne sais pas comment le résoudre ...

44
Melursus

Vous devez exécuter ceci comme un sp dynamique comme

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

Ceci est un exemple où j'utilise la variable de table pour répertorier plusieurs valeurs dans une clause IN. La raison évidente est de ne pouvoir modifier la liste de valeurs qu’un seul endroit dans une procédure longue.

Pour rendre la saisie encore plus dynamique et plus lisible, je suggère de déclarer une variable varchar pour l’entrée, puis d’utiliser un WHILE pour effectuer une boucle dans les données de la variable et les insérer dans la variable de table.

Remplacez @your_list, Your_table et les valeurs par des éléments réels.

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 )

La déclaration select ci-dessous fera la même chose que:

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)

Je sais que je réponds à un ancien message, mais je voulais partager un exemple d'utilisation des tables de variables lorsque l'on veut éviter d'utiliser du SQL dynamique. Je ne suis pas sûr que ce soit le moyen le plus efficace, mais cela a déjà fonctionné pour moi lorsque le SQL dynamique n'était pas une option.

20
Carl Osterman

Vous ne pouvez pas utiliser une variable dans une clause IN - vous devez utiliser SQL dynamique , ou utiliser ne fonction (TSQL ou CLR) pour convertir la liste de valeurs dans une table .

Exemple de SQL dynamique:

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

Tout d’abord, créez une fonction rapide qui divisera une liste de valeurs délimitée dans un tableau, comme ceci:

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 

Appelez ensuite la fonction comme ceci ...

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

Cela a très bien fonctionné sur notre projet ...

Bien entendu, le contraire pourrait également être fait, le cas échéant (bien que ce ne soit pas votre question).

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

Et cela est très utile lorsque vous traitez avec des rapports ayant une liste de paramètres à sélection multiple facultative. Si le paramètre est NULL, vous souhaitez que toutes les valeurs soient sélectionnées, mais s'il contient une ou plusieurs valeurs, vous souhaitez que les données du rapport soient filtrées sur ces valeurs. Ensuite, utilisez SQL comme ceci:

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

Ainsi, si @ExcludeList est une valeur NULL, la clause OR dans la jointure devient un commutateur qui désactive le filtrage sur cette valeur. Très pratique ...

5
laughsloudly

Je pense que le problème est dans

3 + ', ' + 4

changez le en

'3' + ', ' + '4'

DECLARE @ExcludedList VARCHAR(MAX)

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

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

SET @ExcludedListe pour que votre requête devienne

soit

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

o

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

J'ai une autre solution pour le faire sans requête dynamique. Nous pouvons également le faire avec l’aide de 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)

Voici la solution complète: http://raresql.com/2011/12/21/how-to-use-multiple-values-for-in-clause-using-same-parameter -sql-server/

1
user1059637

Essaye ça:

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

Et puis appelez ça comme ça:

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