IN 연산자와 함께 사용할 변수 정의 (T-SQL)


138

IN 연산자를 사용하는 Transact-SQL 쿼리가 있습니다. 이 같은:

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

전체 목록 "(1,2,3,4)"를 보유 할 변수를 정의하는 방법이 있습니까? 어떻게 정의해야합니까?

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

7
이 질문은 "SQL IN 절 매개 변수화"질문과 동일하지 않습니다. 이 질문은 네이티브 T-SQL을 나타내고 다른 질문은 C #을 나타냅니다.
Slogmeister Extraordinaire

답변:


113
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)

47
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)

T-SQL은 말한다[Err] 42000 - [SQL Server]Must declare the scalar variable "@mylist".
시스 Timmerman

1
@ 폴 당신을 위해 그것을 고정
스테판 Z 카밀레

5
(VALUES (1),(2),(3),(4),(5))직접 사용할 수 있습니까?
toddmo

이것이 내 요구에 가장 적합한 솔루션이었습니다. Select에서 얻은 ID 목록으로 변수가 필요하므로 값이 미리 결정되지 않았습니다. 이것은 내가 필요한 것을 정확하게 달성했습니다. 감사!
Lexi847942

12

TSQL 쿼리에 대한 동적 csv 목록을 처리하는 방법에는 두 가지가 있습니다.

1) 내부 선택 사용

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

2) 동적으로 연결된 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) 가능한 세 번째 옵션은 테이블 변수입니다. SQl Server 2005가있는 경우 테이블 변수를 사용할 수 있습니다. Sql Server 2008을 사용하는 경우 전체 테이블 변수를 저장 프로 시저에 매개 변수로 전달하여 조인 또는 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)

5
@ badbod99-그게 일반화와 모든 일반화가 잘못되었습니다 :) 대안을 제안했습니다
hollystyles

1
@Vilx-변수 @list를 설정 하시겠습니까? 그렇게 설정하면 괜찮지 만 하나의 변수 만 설정하면 select를 사용하여 하나의 명령문에 여러 변수를 채울 수 있습니다. 그들 사이에는별로 없기 때문에 항상 SELECT를 사용하는 습관이 있습니다.
hollystyles

1
사실 ... 매우 일반적입니다. 당신의 대안이 더 낫습니다. 나는 실제로 SQL 스크립트 내에서 SQL을 생성하면 유지 보수 할 수없는 코드, 주입 공격의 위험 및 다른 불쾌감을 유발합니다.
badbod99 2009

9

다음과 같은 기능을 사용하십시오.

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;

like를 사용하는 대신 함수가 반환 한 테이블로 내부 조인을 만듭니다.

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

된다

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

인덱싱되지 않은 1M 레코드 테이블에서 두 번째 버전은 약 절반의 시간이 걸렸습니다 ...

건배


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

긴 목록 또는 프로덕션 시스템의 경우 (8000+ 항목 목록을 사용하여 테스트 한) 간단한 IN연산자 보다 훨씬 느릴 수 someColumnName in (1,2,3,4)있으므로이 방법을 사용하지 않는 것이 좋습니다.


4

아니요, 그러한 유형은 없습니다. 그러나 몇 가지 선택이 있습니다.

  • 동적으로 생성 된 쿼리 (sp_executesql)
  • 임시 테이블
  • 테이블 타입 변수 (리스트에 가장 가까운 것)
  • XML 문자열을 생성 한 다음 XML 함수를 사용하여 테이블로 변환하십시오 (시작할 XML이없는 경우에는 실제로 어색하고 원형입니다)

이것들 중 어느 것도 정말로 우아하지는 않지만, 그것이 최고입니다.


4

@LukeH가 약간 개선되었으므로 "INSERT INTO"를 반복 할 필요가 없습니다 : @ realPT 's answer-SELECT를 가질 필요가 없습니다 :

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

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

4

나는 이것이 오래되었다는 것을 알고 있지만 TSQL => 2016, STRING_SPLIT을 사용할 수 있습니다.

DECLARE @InList varchar(255) = 'This;Is;My;List';

WITH InList (Item) AS (
    SELECT value FROM STRING_SPLIT(@InList, ';')
)

SELECT * 
FROM [Table]
WHERE [Item] IN (SELECT Tag FROM InList)

4

SQL2017부터 STRING_SPLIT 을 사용하여 다음 을 수행 할 수 있습니다 .

declare @myList nvarchar(MAX)
set @myList = '1,2,3,4'
select * from myTable where myColumn in (select value from STRING_SPLIT(@myList,','))

2

두 번째 테이블을 사용하지 않고이 작업을 수행하려면 CAST와 같은 방식으로 비교할 수 있습니다.

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

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

비교중인 필드가 이미 문자열 인 경우 CAST 할 필요가 없습니다.

열 일치와 각 고유 값을 쉼표로 묶으면 정확하게 일치합니다. 그렇지 않으면 ', 4,2,15'가 포함 된 목록에서 1의 값을 찾을 수 있습니다.


1

이전에 아무도 언급하지 않았 듯이 Sql Server 2016부터는 json 배열을 사용할 수 있습니다 OPENJSON (Transact-SQL).

declare @filter nvarchar(max) = '[1,2]'

select *
from dbo.Test as t
where
    exists (select * from openjson(@filter) as tt where tt.[value] = t.id)

당신은 그것을 테스트 할 수 있습니다 sql fiddle demo

json으로 더 복잡한 경우도 쉽게 처리 할 수 ​​있습니다. SQL 변수와 함께 WHERE IN 절을 사용하여 SQL에서 값 및 범위 검색 목록을 참조하십시오 .


1

이것은 PATINDEX를 사용하여 테이블의 ID를 숫자가 아닌 정수 목록과 일치시킵니다.

-- Given a string @myList containing character delimited integers 
-- (supports any non digit delimiter)
DECLARE @myList VARCHAR(MAX) = '1,2,3,4,42'

SELECT * FROM [MyTable]
    WHERE 
        -- When the Id is at the leftmost position 
        -- (nothing to its left and anything to its right after a non digit char) 
        PATINDEX(CAST([Id] AS VARCHAR)+'[^0-9]%', @myList)>0 
        OR
        -- When the Id is at the rightmost position
        -- (anything to its left before a non digit char and nothing to its right) 
        PATINDEX('%[^0-9]'+CAST([Id] AS VARCHAR), @myList)>0
        OR
        -- When the Id is between two delimiters 
        -- (anything to its left and right after two non digit chars)
        PATINDEX('%[^0-9]'+CAST([Id] AS VARCHAR)+'[^0-9]%', @myList)>0
        OR
        -- When the Id is equal to the list
        -- (if there is only one Id in the list)
        CAST([Id] AS VARCHAR)=@myList

노트:

  • varchar로 캐스팅하고 괄호 안에 바이트 크기를 지정하지 않으면 기본 길이는 30입니다.
  • % (와일드 카드)는 0 개 이상의 문자 문자열과 일치합니다.
  • ^ (와일드 카드)가 일치하지 않습니다
  • [^ 0-9]는 숫자가 아닌 문자와 일치합니다.
  • PATINDEX는 문자열에서 패턴의 위치를 ​​반환하는 SQL 표준 함수입니다.

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;

5
거기에 코드를 설명하면 더 나은 답변이 될 것입니다!
Deep Kakkar

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.