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.