PostgreSQL에서 두 테이블의 내용이 동일한 지 확인


28

이것은 이미 Stack Overflow 에서 요청 되었지만 MySQL에만 해당됩니다. PostgreSQL을 사용하고 있습니다. 불행하게도 (그리고 놀랍게도) PostgreSQL에는 같은 것이없는 것 같습니다 CHECKSUM table.

PostgreSQL 솔루션은 문제가 없지만 일반적인 솔루션이 더 좋습니다. http://www.besttechtools.com/articles/article/sql-query-to-check-two-tables-have-identical-data를 찾았 지만 사용 된 논리를 이해하지 못합니다.

배경 : 데이터베이스 생성 코드를 다시 작성 했으므로 이전 코드와 새 코드가 동일한 결과를 생성하는지 확인해야합니다.


3
를 사용하여 EXCEPT다음 질문을 확인할 수 있습니다 . SQL에서 두 개의 큰 데이터 세트를 비교하는 효율적인 방법
ypercubeᵀᴹ

pg_comparator 는 효율적인 테이블 내용 비교 및 ​​동기화
natmaka

@natmaka 별도의 답변이되어야합니까?
Faheem Mitha

답변:


24

한 가지 옵션은 다음 형식으로 두 테이블간에 FULL OUTER JOIN을 사용하는 것입니다.

SELECT count (1)
    FROM table_a a
    FULL OUTER JOIN table_b b 
        USING (<list of columns to compare>)
    WHERE a.id IS NULL
        OR b.id IS NULL ;

예를 들면 다음과 같습니다.

CREATE TABLE a (id int, val text);
INSERT INTO a VALUES (1, 'foo'), (2, 'bar');

CREATE TABLE b (id int, val text);
INSERT INTO b VALUES (1, 'foo'), (3, 'bar');

SELECT count (1)
    FROM a
    FULL OUTER JOIN b 
        USING (id, val)
    WHERE a.id IS NULL
        OR b.id IS NULL ;

반면에 카운트는 2를 반환합니다.

CREATE TABLE a (id int, val text);
INSERT INTO a VALUES (1, 'foo'), (2, 'bar');

CREATE TABLE b (id int, val text);
INSERT INTO b VALUES (1, 'foo'), (2, 'bar');

SELECT count (1)
    FROM a
    FULL OUTER JOIN b 
        USING (id, val)
    WHERE a.id IS NULL
        OR b.id IS NULL ;

카운트 0에 대한 희망을 반환합니다.

이 방법에 대해 내가 좋아하는 것은 EXISTS를 사용할 때 각 테이블을 한 번만 읽는 것과 비교하여 각 테이블을 두 번만 읽는다는 것입니다. 또한 이것은 Postgresql뿐만 아니라 전체 외부 조인을 지원하는 모든 데이터베이스에서도 작동합니다.

나는 일반적으로 USING 조항의 사용을 권장하지 않지만 여기에 그것이 더 나은 접근법이라고 믿는 한 가지 상황이 있습니다.

부록 2019-05-03 :

가능한 null 데이터에 문제가있는 경우 (예 : id 열은 nullable이 아니지만 val은 is) 다음을 시도 할 수 있습니다.

SELECT count (1)
    FROM a
    FULL OUTER JOIN b
        ON ( a.id = b.id
            AND a.val IS NOT DISTINCT FROM b.val )
    WHERE a.id IS NULL
        OR b.id IS NULL ;

val이 널 입력 가능하면 실패하지 않습니까?
Amit Goldstein

@AmitGoldstein-null은 문제가 될 것입니다. 그것에 대한 하나의 가능한 해결책에 대해서는 내 부록을 참조하십시오.
gsiems

30

EXCEPT연산자 를 사용할 수 있습니다 . 예를 들어, 테이블의 구조가 동일한 경우 다음은 한 테이블에 있지만 다른 테이블에는없는 모든 행을 리턴합니다 (테이블에 동일한 데이터가있는 경우 0 행).

(TABLE a EXCEPT TABLE b)
UNION ALL
(TABLE b EXCEPT TABLE a) ;

또는 EXISTS부울 값 또는 두 가지 가능한 결과 중 하나를 가진 문자열 만 반환합니다.

SELECT CASE WHEN EXISTS (TABLE a EXCEPT TABLE b)
              OR EXISTS (TABLE b EXCEPT TABLE a)
            THEN 'different'
            ELSE 'same'
       END AS result ;

SQLfiddle 에서 테스트


또한 EXCEPT중복 을 제거 하는 것은 아닙니다 (테이블에 일부 PRIMARY KEY또는 UNIQUE제약 조건 이있는 경우 걱정할 필요는 없지만 중복 행을 생성 할 수있는 임의의 쿼리 결과를 비교하는 경우 걱정할 수 있습니다).

EXCEPT키워드가 수행 하는 또 다른 기능 은 NULL값을 동일하게 취급 하므로 테이블 A에 행이 (1,2,NULL)있고 테이블 B에 행이있는 (1,2,NULL)경우 첫 번째 쿼리는 이러한 행을 표시하지 않으며 'same'두 테이블에 다른 행이 없으면 두 번째 쿼리가 반환 됩니다.

이러한 행을 다른 것으로 계산하려면 gsiems의 FULL JOIN답변 에 변형을 사용하여 모든 (다른) 행을 얻을 수 있습니다.

SELECT *
FROM a NATURAL FULL JOIN b
WHERE a.some_not_null_column IS NULL 
   OR b.some_not_null_column IS NULL ;

예 / 아니오 답변을 얻으려면 :

SELECT CASE WHEN EXISTS
            ( SELECT *
              FROM a NATURAL FULL JOIN b
              WHERE a.some_not_null_column IS NULL 
                 OR b.some_not_null_column IS NULL
            )
            THEN 'different'
            ELSE 'same'
       END AS result ;

두 테이블의 모든 열이 널 입력 가능하지 않은 경우 두 방법은 동일한 대답을 제공합니다.


더 효율적인 방법이있을 수 있습니다. 확실하지 않습니다.
ypercubeᵀᴹ

@FaheemMitha 당신은 이것을 사용하여 모든 것보다 적은 열을 비교할 수 있습니다. SELECT <column_list> FROM a대신 사용하십시오TABLE a
ypercubeᵀᴹ

2
EXCEPT쿼리는 근사한입니다!
Erwin Brandstetter 1

예외 쿼리는 달콤합니다!
sharadov

1

제외 조항이 필요합니다.

SELECT * FROM first_table
EXCEPT
SELECT * FROM second_table

첫 번째 테이블에서 두 번째 테이블에없는 모든 행을 반환합니다.


0

이해하지 못하는 링크 된 코드를 보면 :

select count(*) from
(
select * From EmpDtl1
union
select * From EmpDtl2
)

비밀 소스는 union반대로 사용하고 union all있습니다. 전자는 별개의 행만 유지하고 후자는 중복을 유지합니다 ( reference ). 즉, 중첩 된 쿼리는 "EmpDtl1 및 EmpDtl1에 아직없는 EmpDtl2의 행과 열을 모두 제공합니다"라고 말합니다. 이 서브 쿼리의 수는 EmpDtl2가 결과에 행을 제공하지 않는 경우에만 두 개의 테이블이 동일한 경우에만 EmpDtl1의 수와 같습니다.

또는 키 순서대로 테이블을 두 개의 텍스트 파일로 덤프하고 선택한 비교 도구를 사용하십시오.


3
때 케이스를 검색하지 않습니다 EmpDtl2 이상의 행을 EmpDtl1기존의 모든 행에 존재 할 EmpDtl1.
a_horse_with_no_name
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.