2009-11-10 9 views
82

Mam Transact-SQL kwerendy, która używa operatora IN. Coś takiego:Definiowanie zmiennej do użycia z operatorem IN (T-SQL)

select * from myTable where myColumn in (1,2,3,4) 

Czy istnieje sposób na zdefiniowanie zmiennej do przechowywania całej listy "(1,2,3,4)"? Jak mam to zdefiniować?

declare @myList {data type} 
set @myList = (1,2,3,4) 
select * from myTable where myColumn in @myList 
+5

To pytanie nie jest tożsame z pytaniem "Sparametryzuj zapytanie SQL IN". To pytanie dotyczy natywnego T-SQL, inne pytanie dotyczy C#. –

Odpowiedz

0

Myślę, że będziesz musiał zadeklarować ciąg znaków, a następnie wykonać ten ciąg znaków.

Wystarczy popatrzeć na sp_executesql

6

Istnieją dwa sposoby Tackle dynamicznych list csv dla zapytań TSQL:

1) za pomocą wewnętrznej wybierz

SELECT * FROM myTable WHERE myColumn in (SELECT id FROM myIdTable WHERE id > 10) 

2) Korzystanie dynamicznie doklejane TSQL

DECLARE @sql varchar(max) 
declare @list varchar(256) 
select @list = '1,2,3' 
SELECT @sql = 'SELECT * FROM myTable WHERE myColumn in (' + @list + ')' 

exec sp_executeSQL @sql 

3) Ewentualną trzecią opcją są zmienne w tabeli. Jeśli masz serwer SQl 2005, możesz użyć zmiennej tabeli. Jeśli na serwerze Sql Server 2008 można nawet przekazywać całe zmienne tabeli jako parametr do procedur składowanych i używać go w łączeniu lub jako podselekcję w klauzuli IN.

DECLARE @list TABLE (Id INT) 

INSERT INTO @list(Id) 
SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 


SELECT 
    * 
FROM 
    myTable 
    JOIN @list l ON myTable.myColumn = l.Id 

SELECT 
    * 
FROM 
    myTable 
WHERE 
    myColumn IN (SELECT Id FROM @list) 
+2

Dynamiczny SQL = zło – badbod99

+0

Wiesz, jest też słowo kluczowe "zestaw" ... –

+4

@ badbod99 - To generalizacja i wszystkie uogólnienia są złe :) Oferowałem alternatywy –

77
DECLARE @MyList TABLE (Value INT) 
INSERT INTO @MyList VALUES (1) 
INSERT INTO @MyList VALUES (2) 
INSERT INTO @MyList VALUES (3) 
INSERT INTO @MyList VALUES (4) 

SELECT * 
FROM MyTable 
WHERE MyColumn IN (SELECT Value FROM @MyList) 
2

Nie, nie ma takiego typu. Ale istnieje kilka możliwości:

  • Dynamicznie generowane zapytań (sp_executesql)
  • tabele tymczasowe
  • zmienne Tabela typu (najbliższa rzecz, że nie ma na liście)
  • Załóż łańcuch XML, a następnie przekonwertować do tabeli z funkcjami XML (naprawdę niewygodne i okrężne, chyba że masz XML na początek)

Żadne z nich nie są naprawdę eleganckie, ale najlepsze z nich.

7

Użyj funkcję tak:

CREATE function [dbo].[list_to_table] (@list varchar(4000)) 
returns @tab table (item varchar(100)) 
begin 

if CHARINDEX(',',@list) = 0 or CHARINDEX(',',@list) is null 
begin 
    insert into @tab (item) values (@list); 
    return; 
end 


declare @c_pos int; 
declare @n_pos int; 
declare @l_pos int; 

set @c_pos = 0; 
set @n_pos = CHARINDEX(',',@list,@c_pos); 

while @n_pos > 0 
begin 
    insert into @tab (item) values (SUBSTRING(@list,@c_pos+1,@n_pos - @c_pos-1)); 
    set @c_pos = @n_pos; 
    set @l_pos = @n_pos; 
    set @n_pos = CHARINDEX(',',@list,@c_pos+1); 
end; 

insert into @tab (item) values (SUBSTRING(@list,@l_pos+1,4000)); 

return; 
end; 

Zamiast jak, zrobić sprzężenie wewnętrzne z tabeli zwracanej przez funkcję:

select * from table_1 where id in ('a','b','c') 

staje

select * from table_1 a inner join [dbo].[list_to_table] ('a,b,c') b on (a.id = b.item) 

W nieindeksowanej tabeli rekordów 1M druga wersja zajęła mniej więcej połowę czasu ...

okrzyki

33
DECLARE @mylist TABLE (Id int) 
INSERT INTO @mylist 
SELECT id FROM (VALUES (1),(2),(3),(4),(5)) AS tbl(id) 

SELECT * FROM Mytable WHERE theColumn IN (select id from @mylist) 
+0

T-SQL mówi: "[Err] 42000 - [SQL Server] Musi zadeklarować zmienną skalarną" @mylist "." –

+0

Naprawiono dla ciebie @Paul –

+2

Czy możesz po prostu użyć '(VALUES (1), (2), (3), (4), (5)) 'bezpośrednio? – toddmo

1

Jeśli chcesz to zrobić bez korzystania z drugiej tabeli, można zrobić LIKE porównania z Występują:

DECLARE @myList varchar(15) 
SET @myList = ',1,2,3,4,' 

SELECT * 
FROM myTable 
WHERE @myList LIKE '%,' + CAST(myColumn AS varchar(15)) + ',%' 

Jeśli pole jesteś porównanie jest już ciąg znaków, wtedy nie będziesz musiał CAST.

Otaczanie zarówno dopasowania kolumny, jak i każdej unikatowej wartości w przecinkach zapewnia dokładne dopasowanie. W przeciwnym razie wartość 1 będzie można znaleźć w wykazie zawierającym „4,2,15,”

0
DECLARE @StatusList varchar(MAX); 
SET @StatusList='1,2,3,4'; 
DECLARE @Status SYS_INTEGERS; 
INSERT INTO @Status 
SELECT Value 
FROM dbo.SYS_SPLITTOINTEGERS_FN(@StatusList, ','); 
SELECT Value From @Status; 
+2

będzie lepszą odpowiedzią, jeśli opiszemy tam Twój kod! – Deep

3
DECLARE @myList TABLE (Id BIGINT) INSERT INTO @myList(Id) VALUES (1),(2),(3),(4); 
select * from myTable where myColumn in(select Id from @myList) 

Należy pamiętać, że na długiej liście lub systemów produkcyjnych nie jest to zalecane, aby użyć tego sposobu, jak to może być znacznie wolniejszy niż prosty operator IN, taki jak someColumnName in (1,2,3,4) (testowany przy użyciu 8000 listy elementów)

Powiązane problemy