prosource

SQL WHERE...IN 절 다중 열

probook 2023. 4. 8. 08:39
반응형

SQL WHERE...IN 절 다중 열

SQL Server에 다음 쿼리를 구현해야 합니다.

select *
from table1
WHERE  (CM_PLAN_ID,Individual_ID)
IN
(
 Select CM_PLAN_ID, Individual_ID
 From CRM_VCM_CURRENT_LEAD_STATUS
 Where Lead_Key = :_Lead_Key
)

하지만 WHERE는..IN 절은 열을 하나만 허용합니다.두 개 이상의 열을 다른 내부 SELECT와 비교하려면 어떻게 해야 합니까?

대신 WHERE EXISTES 구문을 사용해야 합니다.

SELECT *
FROM table1
WHERE EXISTS (SELECT *
              FROM table2
              WHERE Lead_Key = @Lead_Key
                        AND table1.CM_PLAN_ID = table2.CM_PLAN_ID
                        AND table1.Individual_ID = table2.Individual_ID)

서브쿼리에서 파생테이블을 생성하여 table1을 다음 파생테이블에 결합할 수 있습니다.

select * from table1 LEFT JOIN 
(
   Select CM_PLAN_ID, Individual_ID
   From CRM_VCM_CURRENT_LEAD_STATUS
   Where Lead_Key = :_Lead_Key
) table2
ON 
   table1.CM_PLAN_ID=table2.CM_PLAN_ID
   AND table1.Individual=table2.Individual
WHERE table2.CM_PLAN_ID IS NOT NULL

솔루션에 대한 경고:

행이 고유하지 않으면 많은 기존 솔루션이 잘못된 출력을 제공합니다.

테이블을 작성하는 유일한 사용자일 경우, 이것은 관련이 없을 수 있지만 테이블 중 하나에 고유한 행이 포함되지 않을 수 있는 경우 여러 솔루션이 해당 코드와 다른 수의 출력 행을 제공합니다.

문제 설명에 대한 경고:

여러 개의 열이 존재하지 않는 경우 무엇을 원하는지 신중하게 고려하십시오.

2개의 컬럼이 있는 in을 보면 다음 2개의 의미를 알 수 있습니다.

  1. 열 a와 열 b의 값은 다른 표에서 독립적으로 표시됩니다.
  2. 열 a와 열 b의 값이 다른 테이블에 같은 행에 함께 표시됩니다.

시나리오 1은 매우 사소한 것입니다.단순히 2개의 IN 문을 사용합니다.

대부분의 기존 답변에 따라 시나리오 2에 대한 언급 및 추가 접근법의 개요(및 간단한 판단)를 제공한다.

EXISTES(안전, SQL Server 권장)

@mrdenny에서 제공하는 바와 같이, EXISTS는 당신이 찾고 있는 것과 정확히 일치합니다.이 예는 다음과 같습니다.

SELECT * FROM T1
WHERE EXISTS
(SELECT * FROM T2 
 WHERE T1.a=T2.a and T1.b=T2.b)

LEFT SEMI JOIN(안전, 이를 지원하는 방언에 권장)

이 방법은 매우 간결하지만 SQL Server를 포함한 대부분의 SQL 방언은 현재 지원하지 않습니다.

SELECT * FROM T1
LEFT SEMI JOIN T2 ON T1.a=T2.a and T1.b=T2.b

다중 IN 문(안전하지만 코드 중복에 주의)

@cataclysm에서 언급한 바와 같이 2개의 IN 문을 사용하는 것도 효과적인 방법입니다.아마 다른 솔루션보다 성능이 뛰어날 수도 있습니다.단, 매우 주의해야 할 것은 코드 복제입니다.다른 테이블에서 선택하거나 where 문을 변경할 경우 논리 불일치가 발생할 위험이 높아집니다.

기본 솔루션

SELECT * from T1
WHERE a IN (SELECT a FROM T2 WHERE something)
AND b IN (SELECT b FROM T2 WHERE something)

코드 중복이 없는 솔루션(일반 SQL Server 쿼리에서 작동하지 않을 수 있음)

WITH mytmp AS (SELECT a, b FROM T2 WHERE something);
SELECT * from T1 
WHERE a IN (SELECT a FROM mytmp)
AND b IN (SELECT b FROM mytmp)

INSER JOIN(기술적으로는 안전할 수 있지만 대부분의 경우 그렇지 않음)

필터로서 내부 조인 사용을 권장하지 않는 이유는 실제로는 오른쪽 테이블의 중복으로 인해 왼쪽 테이블의 중복이 발생하는 경우가 많기 때문입니다.그리고 설상가상으로 최종 결과를 명확하게 할 수 있지만, 실제로는 왼쪽 표가 고유할 필요가 없을 수도 있습니다(또는 선택한 열에서 고유하지 않을 수도 있습니다.또한 왼쪽 테이블에 존재하지 않는 열을 실제로 선택할 수 있습니다.

SELECT T1.* FROM T1
INNER JOIN 
(SELECT DISTINCT a, b FROM T2) AS T2sub
ON T1.a=T2sub.a AND T1.b=T2sub.b

가장 흔한 실수:

  1. 안전한 서브쿼리 없이 T2에 직접 접속합니다.중복의 위험이 있다)
  2. SELECT * (T2에서 열을 가져오기 위해 구아레인화됨)
  3. SELECT c(열은 항상 T1에서 오는 것을 보증하지 않습니다)
  4. 잘못된 위치에 구별되거나 구별되지 않음

컬럼과 분리기 연결(안전하지 않은, 끔찍한 성능)

기능적 문제는 열에 발생할 수 있는 구분 기호를 사용하면 결과가 100% 정확하도록 하는 것이 까다롭다는 것입니다.기술적인 문제는 이 방법이 종종 유형 변환을 유발하고 인덱스를 완전히 무시하기 때문에 성능이 저하될 수 있다는 것입니다.이러한 문제에도 불구하고 소규모 데이터셋의 임시 쿼리에 여전히 이 기능을 사용하고 있다는 것을 인정해야 합니다.

SELECT * FROM T1
WHERE CONCAT(a,"_",b) IN 
(SELECT CONCAT(a,"_",b) FROM T2)

열이 숫자일 경우 일부 SQL 방언에서는 먼저 열을 문자열로 캐스트해야 합니다.SQL Server가 자동으로 이 작업을 수행할 것이라고 생각합니다.


정리하면: SQL에서 이 작업을 수행하는 방법은 여러 가지가 있습니다.안전한 선택을 하면 놀라움을 피할 수 있고 장기적으로 시간과 헤드스케이스를 절약할 수 있습니다.

select * from tab1 where (col1,col2) in (select col1,col2 from tab2)


Oracle은 선택한 열 중 하나 이상이 NULL인 행을 무시합니다. 이 경우 NVL-Funktion을 사용하여 NULL을 특별한 값(값에는 포함되지 않아야 함)에 매핑할 수 있습니다.

select * from tab1
where (col1, NVL(col2, '---') in (select col1, NVL(col2, '---') from tab2)

단순 EXISTS 절이 가장 깨끗합니다.

select *
from table1 t1
WHERE
EXISTS
(
 Select * --or 1. No difference...
 From CRM_VCM_CURRENT_LEAD_STATUS Ex
 Where Lead_Key = :_Lead_Key
-- correlation here...
AND
t1.CM_PLAN_ID = Ex.CM_PLAN_ID AND t1.CM_PLAN_ID =  Ex.Individual_ID
)

상관관계에 여러 행이 있는 경우 JOIN은 출력에 여러 행을 제공하기 때문에 구별이 필요합니다.그 때문에, 통상, EXIST가 보다 효율이 향상됩니다.

: ★SELECT *하면 행 의 OIN을 사용하면 행 제한 테이블의 열도 포함됩니다.

일반 내부 조인만 수행할 수 있는데 WHERE EXISTS 또는 DERVENED TABles를 사용하는 이유는 무엇입니까?

SELECT t.*
FROM table1 t
INNER JOIN CRM_VCM_CURRENT_LEAD_STATUS s
    ON t.CM_PLAN_ID = s.CM_PLAN_ID
    AND t.Individual_ID = s.Individual_ID
WHERE s.Lead_Key = :_Lead_Key

(CM_PLAN_ID, Individual_)의 쌍인 경우ID)는 상태 테이블에서 고유하지 않습니다.대신 SELECT DISTINCT t.*가 필요할 수 있습니다.

Postgres SQL  : version 9.6
Total records on tables : mjr_agent = 145, mjr_transaction_item = 91800

1. 와의 사용EXISTS[평균 쿼리 시간 : 1.42초]

SELECT count(txi.id) 
FROM 
mjr_transaction_item txi
WHERE 
EXISTS ( SELECT 1 FROM mjr_agent agnt WHERE agnt.agent_group = 0 AND (txi.src_id = agnt.code OR txi.dest_id = agnt.code) ) 

2. 2줄로 사용IN조항 [평균 쿼리 시간: 0.37초]

SELECT count(txi.id) FROM mjr_transaction_item txi
WHERE 
txi.src_id IN ( SELECT agnt.code FROM mjr_agent agnt WHERE agnt.agent_group = 0 ) 
OR txi.dest_id IN ( SELECT agnt.code FROM mjr_agent agnt WHERE agnt.agent_group = 0 )

3. 와의 사용INNNER JOIN패턴 [평균 쿼리 시간: 2.9초]

SELECT count(DISTINCT(txi.id)) FROM mjr_transaction_item txi
INNER JOIN mjr_agent agnt ON agnt.code = txi.src_id OR agnt.code = txi.dest_id
WHERE 
agnt.agent_group = 0

그래서 두 번째 옵션을 선택했습니다.

*** T-SQL ***

값싼 해킹으로 string_agg를 사용하여 값싼 정규화를 얻었어요.(멀티플렉스입니다.너무 힘들다는 거 알아요.80년대 스타일의 상자 그림으로 당신의 고통을 보상해 드렸습니다.즐겨보세요!~)

여기 샘플이 있습니다(이름 치환에 재미를 느꼈습니다:D)

select 
    vendorId,   
    affiliate_type_code, 
    parent_vendor_id,
    state_abbr,
    county_abbr,
    litigation_activity_indicator,
    string_agg(employee_id,',') as employee_ids,
    string_agg(employee_in_deep_doodoo,',') as 'employee-inventory connections'
from (
    select distinct top 10000 -- so I could pre-order my employee id's - didn't want mixed sorting in those concats
    mi.missing_invintory_identifier as rqid,
    vendorId,   
    affiliate_type_code, 
    parent_vendor_id,
    state_abbr,
    county_abbr,
    litigation_activity_indicator,
    employee_identifier as employee_id,
    concat(employee_identifier,'-',mi.missing_invintory_identifier) as employee_in_deep_doodoo
    from 
        missing_invintory as mi 
        inner join vendor_employee_view as ev
        on mi.missing_invintory_identifier = ev.missing_invintory_identifier        
    where ev.litigation_activity_indicator = 'N'
    order by employee_identifier desc

)  as x
    group by 
    vendorId,   
    affiliate_type_code, 
    parent_vendor_id,
    state_abbr,
    county_abbr,
    litigation_activity_indicator
    having count(employee_id) > 1



┏━━━━━━━━━━┳━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃ vendorId ┃ affiliate_type ┃ parent_vendor_id ┃ state_abbr ┃ county_abbr       ┃ litigation_indicator ┃ employee_ids        ┃ employee-inventory connections ┃
┣━━━━━━━━━━╋━━━━━━━━━━━━━━━━╋━━━━━━━━━━━━━━━━━━╋━━━━━━━━━━━━╋━━━━━━━━━━━━━━━━━━━╋━━━━━━━━━━━━━━━━━━━━━━╋━━━━━━━━━━━━━━━━━━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫
┃      123 ┃ EXP            ┃               17 ┃ CA         ┃ SDG               ┃ N                    ┃ 112358,445678       ┃ 112358-1212,1534490-1212       ┃
┣━━━━━━━━━━╋━━━━━━━━━━━━━━━━╋━━━━━━━━━━━━━━━━━━╋━━━━━━━━━━━━╋━━━━━━━━━━━━━━━━━━━╋━━━━━━━━━━━━━━━━━━━━━━╋━━━━━━━━━━━━━━━━━━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫
┃     4567 ┃ PRI            ┃              202 ┃ TX         ┃ STB               ┃ Y                    ┃ 998754,332165       ┃ 998754-4545,332165-4545        ┃
┗━━━━━━━━━━┻━━━━━━━━━━━━━━━━┻━━━━━━━━━━━━━━━━━━┻━━━━━━━━━━━━┻━━━━━━━━━━━━━━━━━━━┻━━━━━━━━━━━━━━━━━━━━━━┻━━━━━━━━━━━━━━━━━━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛

쿼리:

select ord_num, agent_code, ord_date, ord_amount
from orders
where (agent_code, ord_amount) IN
(SELECT agent_code, MIN(ord_amount)
FROM orders 
GROUP BY agent_code);

위의 쿼리는 mysql에서 동작했습니다.다음 링크를 참조해 주세요. -- >

https://www.w3resource.com/sql/subqueries/multiplee-row-column-subqueries.php

어떤 형태로든 열을 연결하는 것은 "해킹"이지만 제품이 두 개 이상의 열에 대한 세미 조인 기능을 지원하지 않는 경우 어쩔 수 없는 경우가 있습니다.

내부/외부 결합 솔루션이 작동하지 않는 예:

select * from T1 
 where <boolean expression>
   and (<boolean expression> OR (ColA, ColB) in (select A, B ...))
   and <boolean expression>
   ...

쿼리가 단순하지 않은 경우 정기적인 내부/외부 조인을 수행하기 위해 기본 테이블 세트에 액세스할 수 없는 경우가 있습니다.

이 "해크"를 사용하는 경우 필드를 결합할 때 필드 사이에 딜리미터를 충분히 추가하여 다음과 같이 오역하지 않도록 하십시오.ColA + ":-:" + ColB

테이블 하나를 원하는 경우 다음 쿼리를 사용합니다.

SELECT S.* 
FROM Student_info S
  INNER JOIN Student_info UT
    ON S.id = UT.id
    AND S.studentName = UT.studentName
where S.id in (1,2) and S.studentName in ('a','b')

및 표 데이터는 다음과 같습니다.

id|name|adde|city
1   a   ad  ca
2   b   bd  bd
3   a   ad  ad
4   b   bd  bd
5   c   cd  cd

다음으로 다음과 같이 출력합니다.

id|name|adde|city
1   a   ad  ca
2   b   bd  bd

우리는 간단히 이것을 할 수 있다.

   select *
   from 
    table1 t, CRM_VCM_CURRENT_LEAD_STATUS c
    WHERE  t.CM_PLAN_ID = c.CRM_VCM_CURRENT_LEAD_STATUS
    and t.Individual_ID = c.Individual_ID

이렇게 하면 쉽게 찾을 수 있었다.

Select * 
from table1 
WHERE  (convert(VARCHAR,CM_PLAN_ID) + convert(VARCHAR,Individual_ID)) 
IN 
(
 Select convert(VARCHAR,CM_PLAN_ID) + convert(VARCHAR,Individual_ID)
 From CRM_VCM_CURRENT_LEAD_STATUS 
 Where Lead_Key = :_Lead_Key 
) 

이것이 도움이 되기를 바랍니다:)

단순하고 잘못된 방법은 +를 사용하여 두 열을 결합하거나 연결해서 하나의 열을 만드는 것입니다.

Select *
from XX
where col1+col2 in (Select col1+col2 from YY)

물론 이건 꽤 느릴 거야.프로그래밍에서는 사용할 수 없지만, 단지 무언가를 사용할 수 있는지 확인하기 위해 쿼리하는 경우입니다.

언급URL : https://stackoverflow.com/questions/1136380/sql-where-in-clause-multiple-columns

반응형