다른 테이블에없는 행을 선택하십시오.


172

두 개의 postgresql 테이블이 있습니다.

table name     column names
-----------    ------------------------
login_log      ip | etc.
ip_location    ip | location | hostname | etc.

login_log에 행이없는 모든 IP 주소를 가져오고 싶습니다 ip_location.
이 쿼리를 시도했지만 구문 오류가 발생합니다.

SELECT login_log.ip 
FROM login_log 
WHERE NOT EXIST (SELECT ip_location.ip
                 FROM ip_location
                 WHERE login_log.ip = ip_location.ip)
ERROR: syntax error at or near "SELECT"
LINE 3: WHERE NOT EXIST (SELECT ip_location.ip`

또한이 쿼리 (작동하도록 조정) 가이 목적에 가장 적합한 쿼리인지 궁금합니다.

답변:


386

이 작업에는 기본적으로 4 가지 기술이 있으며 모두 표준 SQL입니다.

NOT EXISTS

Postgres에서 가장 빠릅니다.

SELECT ip 
FROM   login_log l 
WHERE  NOT EXISTS (
   SELECT  -- SELECT list mostly irrelevant; can just be empty in Postgres
   FROM   ip_location
   WHERE  ip = l.ip
   );

또한 다음을 고려하십시오.

LEFT JOIN / IS NULL

때로는 이것이 가장 빠릅니다. 종종 가장 짧습니다. 종종와 같은 쿼리 계획이 발생 NOT EXISTS합니다.

SELECT l.ip 
FROM   login_log l 
LEFT   JOIN ip_location i USING (ip)  -- short for: ON i.ip = l.ip
WHERE  i.ip IS NULL;

EXCEPT

짧은. 보다 복잡한 쿼리에는 쉽게 통합되지 않습니다.

SELECT ip 
FROM   login_log

EXCEPT ALL  -- "ALL" keeps duplicates and makes it faster
SELECT ip
FROM   ip_location;

( 문서 당 ) :

EXCEPT ALL사용 하지 않으면 중복이 제거 됩니다.

일반적으로 ALL키워드가 필요합니다 . 신경 쓰지 않아도 쿼리 속도가 빨라지 므로 계속 사용하십시오 .

NOT IN

NULL값이 없거나 NULL올바르게 처리 해야하는 경우 에만 적합합니다. 나는 이것을 목적으로 사용 하지 않을 것입니다. 또한 테이블이 클수록 성능이 저하 될 수 있습니다.

SELECT ip 
FROM   login_log
WHERE  ip NOT IN (
   SELECT DISTINCT ip  -- DISTINCT is optional
   FROM   ip_location
   );

NOT INNULL양쪽의 값에 대한 "트랩"을 전달합니다 .

MySQL을 대상으로 한 dba.SE에 대한 비슷한 질문 :


2
두 테이블 모두에서 데이터 볼륨이 높을 때 어떤 SQL이 더 빠르게 실행됩니까? (십억으로 가정)
Teja

EXCEPT ALL은 저에게 가장 빠릅니다
Dan Parker

조심 LEFT JOIN- 조회 테이블에 여러 개의 매칭되는 열이있는 경우,이 원하는되지 않을 수 있습니다 일치하는 각 행에 대한 기본 쿼리에서 중복 된 항목을 생성합니다.
Matthias Fripp

@MatthiasFripp :이 발생하지 않을 수 있다는 점을 제외하고 WHERE i.ip IS NULL의미가없는, 아니 전혀 일치.
Erwin Brandstetter

@ erwin-brandstetter : 좋은 지적입니다. 나는 여러 개의 긍정적 인 일치 가능성에 대해 생각하면서 넘어졌지만 물론 그것들은 모두 제외 될 것입니다.
Matthias Fripp

2

A.) 명령이 존재하지 않습니다. 'S'가 없습니다.

B.) 대신 NOT IN을 사용하십시오.

SELECT ip 
  FROM login_log 
  WHERE ip NOT IN (
    SELECT ip
    FROM ip_location
  )
;

4
큰 데이터 세트에 NOT IN은 끔찍한 아이디어입니다. 매우 느립니다. 나쁘고 피해야합니다.
Grzegorz Grabek

0

SELECT * FROM testcases1 t WHERE NOT EXISTS ( SELECT 1
FROM executions1 i WHERE t.tc_id = i.tc_id and t.pro_id=i.pro_id and pro_id=7 and version_id=5 ) and pro_id=7 ;

여기서 testcases1 테이블은 모든 데이터를 포함하고 executions1 테이블은 testcases1 테이블 중 일부 데이터를 포함합니다. exections1 테이블에없는 데이터 만 검색하고 있습니다. (그리고 심지어 당신이 줄 수있는 조건을 제공하고 있습니다.) 데이터를 검색 할 때 없어야하는 조건을 지정하십시오. 괄호 안에 있어야합니다.


0

이것은 또한 시도 할 수 있습니다 ...

SELECT l.ip, tbl2.ip as ip2, tbl2.hostname
FROM   login_log l 
LEFT   JOIN (SELECT ip_location.ip, ip_location.hostname
             FROM ip_location
             WHERE ip_location.ip is null)tbl2

2
WHERE ip_location.ip is null-상태는 어떻게 WHERE되나요? 또한 하위 쿼리는 상관 된 쿼리가 아닙니다.
Istiaque Ahmed
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.