2013-06-11 2 views
1

멱등 원 삽입을 수행하는이 github SQL 코드 예제를 발견했습니다. 내가 원하는 방식으로 정확하게 작동합니다. 나는 조금 혼란 스럽기 때문에 EXISTS를 사용하고 싶지 않습니다. 동일한 작업을 조인으로 코딩 할 수 있습니까? https://github.com/imtiazahmad007/SQL-Tips-Techniques/blob/master/Idempotent_Postgres_Inserts.sqlSQL - 멱등 원 대신에 EXISTS 및 NOT EXISTS 대신 조인을 사용하는 방법

INSERT INTO users_articles (date, user_id, hit_count) 
SELECT a.date, a.user_id, sum(a.article_id as hits) 
from (
select t.* from users_article_details AS t 
WHERE NOT EXISTS (
    SELECT 1 
    FROM do_not_email_users_tbl 
    WHERE email = t.email 
    LIMIT 1 
)) a 
WHERE NOT EXISTS 
(SELECT 1 from users_articles b 
WHERE b.date = a.date) 
GROUP BY date, user_id 
+3

어쨌든 잘 쓰여지지 않습니다. 너무 많은 중첩 쿼리, 테이블 별칭의 일관성없는 사용, "안타"가 왜 있는지 알지 못합니다. 존재하지 않는 것은 문제 중 가장 적은 것입니다. 개인적으로 나는 질문의 전제에 동의하지 않습니다. 존재하지 않는 것은 표준적이고 광범위하게 발생하는 SQL입니다. 특히 결과를 달성하는 매우 효율적인 방법입니다 (특히 하위 쿼리가 기본 쿼리에서 전달 된 값에 대해 여러 행을 반환 할 수있는 경우). 쿼리는 옵티 마이저에 의해 효율적인 anti-join으로 변환 될 것입니다. –

+0

prothid와 Bob Jarvis의 답변을 프로파일 링해야합니다. 다른 RDBMS는 다른 성능 특성을 가지며, 하나는 다른 성능 특성보다 훨씬 느릴 수 있습니다. –

+0

Oracle 또는 Postgres 용입니까? 태그가 혼란 스럽습니다. –

답변

1
INSERT INTO 
    users_articles 
    (date, user_id, hit_count) 
SELECT 
    uad.date, 
    uad.user_id, 
    SUM(uad.article_id) AS hits 
FROM 
    users_article_details uad 
WHERE 
    uad.email NOT IN (select email from do_not_email_user_table where email=uad.email) AND 
    uad.date NOT IN (select `date` from users_articles where `date`=uad.date and user_id=uad.user_id) 
GROUP BY 
    uad.date, 
    uad.user_id; 
+1

하위 쿼리에서 조건자를 남겨 둘 수 있습니다. 상관 하위 쿼리에서 NOT IN을 사용하면 약간 이상하게 보입니다. 하위 쿼리 중 하나가 null 값을 반환하는 경우이를 포함 시켰는지 여부는 NOT IN의 단점입니다. –

+0

그냥 읽을 수있는 IMO입니다. 경우에 따라 힌트를 삭제하여 쿼리 플래너에서 향상된 성능을 얻을 수도 있습니다. 또한 제출자가 중복 날짜를 확인할 때 users_articles 테이블에서 사용자 ID를 상호 참조하는 것을 잊어 버린 쿼리에서 오류가 수정되었습니다. – prothid

2

내가 외부를 사용하여 호의를 이런 종류의 일을 위해 조인 :

다음은 내가 GitHub의에서 찾을 같은 코드입니다. 시도 :

INSERT INTO USERS_ARTICLES (DATE, USER_ID, HIT_COUNT) 
    SELECT a.DATE, 
     a.USER_ID, 
     SUM(a.ARTICLE_ID) AS HITS 
    FROM USERS_ARTICLE_DETAILS a 
    LEFT OUTER JOIN DO_NOT_EMAIL_USERS_TBL n 
     ON (n.EMAIL = a.EMAIL) 
    LEFT OUTER JOIN USERS_ARTICLES b 
     ON (b.DATE = a.DATE) 
    WHERE n.EMAIL IS NULL AND 
      b.DATE IS NULL 
    GROUP BY DATE, USER_ID 

을 잠재적으로 문제가 발생할 수 있습니다 열 이름을 예약어 DATE 사용 - 그렇다면, 큰 따옴표 서라운드 DATE (예를 들어, "DATE").

공유하고 즐기십시오.

+0

LEFT OUTER JOIN do_not_email_users_tbl n on (n.email = a.email)'을 users_articles_details하고 있습니다. do_not_email_users_tbl에있는 이메일 주소와 일치하는 사용자 만 필터링합니까? 이메일을 보내고 나머지는 걸러 내도록 허락 한 사용자들만을 원합니다. 왼쪽 외부 조인에 대해 설명해 주시겠습니까? – Doublespeed

+0

@ user2081579 - 왼쪽 외부 조인은 "왼쪽 테이블 (USERS_ARTICLE_DETAILS)의 모든 행을 포함하고 지정된 조건과 일치하는 오른쪽 테이블 (DO_NOT_EMAIL_USERS_TBL 및 USERS_ARTICLES, 별도 조인)의 행에 데이터를 추가합니다"라고 말합니다. WHERE 절에서 오른쪽 행이 발견되면 NULL이 아니어야하는 필드에서 NULL을 찾음으로써 오른쪽 테이블에서 일치하는 항목을 찾지 못한 조인 된 행만 허용합니다. 그래서 DO_NOT_EMAIL_USERS_TBL의 데이터가 없다면 (n.EMAIL이 NULL이기 때문에 이것을 알 수 있습니다) 이메일을 보내면됩니다. 공유하고 즐기십시오. –

+0

@ user2081579 - 추가 정보 - IMO EXISTS/NOT EXISTS보다 조인을 사용하면 성능 이식성이 향상됩니다. 오라클과 같은 일부 데이터베이스는 EXISTS/NOT EXISTS를 동등한 OUTER JOIN으로 변환하는 것에 매우 뛰어납니다. 그러나 다른 곳에서는이 작업을 제대로 수행하지 못하고 EXISTS 하위 테이블을 주 테이블의 개별 행에 대해 수행하려고 시도 할 수 있습니다. 이것은 성능 블랙홀 일 수 있습니다.그러나 적절한 인덱스를 사용하면 대부분의 관계형 데이터베이스가 조인을 관계형 데이터베이스의 기본 요소로 합리적으로 잘 처리 할 수 ​​있습니다. YMMV. –