2012-04-26 15 views
5

Ho il seguente codice, il problema è che il mio elenco di variabili @LocationList è essenzialmente una stringa csv. Quando uso questo come parte del LocationID in (@LocationList) dice che non è un int (LocationID è un int). Come posso ottenere questa stringa csv per essere accettata dalla clausola?SQL in (@Variable) query

Declare @LocationList varchar(1000) 
Set @LocationList = '1,32' 

select Locations from table where Where LocationID in (@LocationList) 
+1

possibile duplicato del [Server SQL SP - Passare parametri per l'elenco di array "IN"?] (http://stackoverflow.com/questions/537087/sql-server-sp-pass-parameter-for-in-array-list) – Lamak

+0

Hai considerato di utilizzare un [parametro tabella-valore ] (http://msdn.microsoft.com/en-us/library/bb510489.aspx). Sarebbe '' selezionare Posizioni dalla tabella dove Dove PosizioneID in (Seleziona posizione da @LocationList) ' –

risposta

5

Il modo più efficace per farlo è con SQL dinamico come rt2800 menzioni (con avvisi di iniezione di Michael Allen)

Tuttavia è possibile effettuare una funzione di:

ALTER FUNCTION [dbo].[CSVStringsToTable_fn] (@array VARCHAR(8000)) 
RETURNS @Table TABLE (value VARCHAR(100)) 
AS 
    BEGIN 
     DECLARE @separator_position INTEGER, 
      @array_value VARCHAR(8000) 

     SET @array = @array + ',' 

     WHILE PATINDEX('%,%', @array) <> 0 
      BEGIN 
       SELECT @separator_position = PATINDEX('%,%', @array) 
       SELECT @array_value = LEFT(@array, @separator_position - 1) 

       INSERT @Table 
       VALUES (@array_value) 

       SELECT @array = STUFF(@array, 1, @separator_position, '') 
      END 
     RETURN 
    END 

e selezionare da esso:

DECLARE @LocationList VARCHAR(1000) 
SET @LocationList = '1,32' 

SELECT Locations 
FROM table 
WHERE LocationID IN (SELECT * 
          FROM  dbo.CSVStringsToTable_fn(@LocationList)) 

O

SELECT Locations 
FROM table loc 
     INNER JOIN dbo.CSVStringsToTable_fn(@LocationList) list 
      ON list.value = loc.LocationID 

che è estremamente utile quando si tenta di inviare un elenco di più valori da SSRS a un PROC.

+0

Si prega di notare che ** potrebbe ** essere necessario eseguire il cast come necessario – SQLMason

+0

Ah questa è una buona idea, grazie –

0
declare @querytext Nvarchar(MAX) 

set @querytext = 'select Locations from table where Where LocationID in (' + @LocationList + ');'; 

exec sp_executesql @querytext; 
+0

Altamente suggerire contro questo approccio, rischio troppo per l'iniezione sql. In generale stai lontano dal metodo exec, è troppo pericoloso. –

+0

@MichaelAllen Dipende da come viene generato il tuo elenco, tuttavia hai ragione su SQL injection e ** sp_executesql ** sarebbe meglio - in quanto può anche memorizzare nella cache il piano di esecuzione. – SQLMason

1

Spesso ho questo requisito e SOMETIME, se si conosce molto bene la colonna su cui si sta cercando [la dimensione/formato/lunghezza], si può fare una specie di REGEX.

Qualcosa di simile a questo:

DECLARE @MyListOfLocation varchar(255) 
    set @MyListOfLocation = '|1|32|36|24|3|' 

    Select LocationID 
    from Table 
    where @MyListOfLocation like '%|' + LocationID + '|%' 

NOTA: il personaggio PIPE è utilizzato per proteggere la query da restituire qualsiasi LocationID che contiene un singolo carattere (la '1', per esempio).

Ecco un esempio di lavoro completo:

DECLARE @MyListOfLocation varchar(255) 
set @MyListOfLocation = '|1|11|21|' 

SELECT LocationName 
FROM (
     select '1' as LocationID, 'My Location 1' as LocationName 
     union all 
     select '11' as LocationID, 'My Location 11' as LocationName 
     union all 
     select '12' as LocationID, 'My Location 12' as LocationName 
     union all 
     select '13' as LocationID, 'My Location 13' as LocationName 
     union all 
     select '21' as LocationID, 'My Location 21' as LocationName 
    ) as MySub 
where @MyListOfLocation like '%|' + LocationID + '|%' 

ATTENZIONE! Questo metodo non è adatto all'Indice!

Se si vuole fare un po 'di aggiungere IN (@MyListOfLocation) in tutto ciò che, di sfruttare l'uso di indici, è possibile modificare lo script fare per:

SELECT MyDATA.* 
FROM HugeTableWithAnIndexOnLocationID as MyDATA 
WHERE LocationID in (
     Select LocationID 
     from Table 
     where @MyListOfLocation like '%|' + LocationID + '|%')