NULLS를 포함 할 수있는 열 비교-더 우아한 방법이 있습니까?


16

나는 당신이 값을 NULL과 비교할 수 없으며 다음 코드와 같은 것을 추가하지 않고 결과를 기대할 수 있다는 것을 알고있다 ...

SELECT
    *
FROM 
    A INNER JOIN 
    B ON A.ID = B.ID
WHERE
    A.STRING <> B.STRING OR (A.STRING IS NULL AND B.STRING IS NOT NULL) OR (A.STRING IS NOT NULL AND B.STRING IS NULL) OR 
    A.DT <> B.DT OR (A.DT IS NULL AND B.DT IS NOT NULL) OR (A.DT IS NOT NULL AND B.DT IS NULL) OR 
    A.B <> B.B OR (A.B IS NULL AND B.B IS NOT NULL) OR (A.B IS NOT NULL AND B.B IS NULL) OR 
    A.NUM <> B.NUM OR (A.NUM IS NULL AND B.NUM IS NOT NULL) OR (A.NUM IS NOT NULL AND B.NUM IS NULL) 

내 질문은 :

둘 중 하나가 null 일 수있는 두 테이블에서 변경된 값을 테스트하는 더 우아한 방법이 있습니까?

솔루션은 여러 데이터 유형에서 균일하게 작동해야합니다.

테스트 테이블을 설정하는 코드는 다음과 같습니다.

CREATE TABLE A
(
    ID INT IDENTITY(1,1) NOT NULL,
    STRING VARCHAR(20) NULL,
    DT DATETIME NULL,
    B BIT NULL,
    NUM INT NULL
)

CREATE TABLE B
(
    ID INT IDENTITY(1,1) NOT NULL,
    STRING VARCHAR(20) NULL,
    DT DATETIME NULL,
    B BIT NULL,
    NUM INT NULL
)


INSERT INTO A (STRING, DT, B, NUM) VALUES ('TEST', '2012-03-16 16:39:04.893', 0, 23)
INSERT INTO A (STRING, DT, B, NUM) VALUES (NULL, '2012-03-16 16:39:04.893', 0, 23)
INSERT INTO A (STRING, DT, B, NUM) VALUES ('TEST', NULL, 0, 23)
INSERT INTO A (STRING, DT, B, NUM) VALUES ('TEST', '2012-03-16 16:39:04.893', NULL, 23)
INSERT INTO A (STRING, DT, B, NUM) VALUES ('TEST', '2012-03-16 16:39:04.893', 0, NULL)
INSERT INTO A (STRING, DT, B, NUM) VALUES ('TEST', '2012-03-16 16:39:04.893', 0, 23)
INSERT INTO A (STRING, DT, B, NUM) VALUES ('TEST', '2012-03-16 16:39:04.893', 0, 23)
INSERT INTO A (STRING, DT, B, NUM) VALUES ('TEST', '2012-03-16 16:39:04.893', 0, 23)
INSERT INTO A (STRING, DT, B, NUM) VALUES ('TEST', '2012-03-16 16:39:04.893', 0, 23)
INSERT INTO A (STRING, DT, B, NUM) VALUES ('TEST', '2012-03-16 16:39:04.893', 0, 23)


INSERT INTO B (STRING, DT, B, NUM) VALUES ('TEST', '2012-03-16 16:39:04.893', 0, 23)
INSERT INTO B (STRING, DT, B, NUM) VALUES ('TEST', '2012-03-16 16:39:04.893', 0, 23)
INSERT INTO B (STRING, DT, B, NUM) VALUES ('TEST', '2012-03-16 16:39:04.893', 0, 23)
INSERT INTO B (STRING, DT, B, NUM) VALUES ('TEST', '2012-03-16 16:39:04.893', 0, 23)
INSERT INTO B (STRING, DT, B, NUM) VALUES ('TEST', '2012-03-16 16:39:04.893', 0, 23)
INSERT INTO B (STRING, DT, B, NUM) VALUES ('STAGE', '2012-03-16 16:39:04.893', 0, 23)
INSERT INTO B (STRING, DT, B, NUM) VALUES ('TEST', '2555-11-11 00:00:00.000', 0, 23)
INSERT INTO B (STRING, DT, B, NUM) VALUES ('TEST', '2012-03-16 16:39:04.893', 0, 23)
INSERT INTO B (STRING, DT, B, NUM) VALUES ('TEST', '2012-03-16 16:39:04.893', 0, 23)
INSERT INTO B (STRING, DT, B, NUM) VALUES ('TEST', '2012-03-16 16:39:04.893', 0, 999)

답변:


24

Paul White문서화되지 않은 쿼리 계획 : 평등 비교 에서이 방법을 사용할 수 있습니다 .

SELECT * 
FROM   A 
       INNER JOIN B 
         ON A.ID = B.ID 
            AND EXISTS(SELECT A.* 
                       EXCEPT 
                       SELECT B.*) 

이것은 훌륭합니다. 테스트 해 보았습니다. 필요한대로 작동하는 것 같습니다. 매우 감사합니다.
GWR

1
그것은 당신이 나를 이길 드래프트! 고백해야하지만이 방법을 가르쳐주었습니다. 너무 아름답습니다. :)
ErikE

마틴,이 방법을 사용하여 데이터 비교하기에 너무 큰 테이블을 비교하고 있습니까?
AK

3

SQL Server 2005 이상에서 지원되는 표준 SQL :

WITH A_MINUS_B 
     AS
     (
      SELECT * 
        FROM A
      EXCEPT 
      SELECT *
        FROM B
     )
SELECT * 
  FROM A_MINUS_B AS T 
       JOIN B ON T.ID = B.ID;

0

이것은 전역적인 접근 방식이므로 질문에서 수정 된 쿼리를 다시 작성하지 않았습니다. 나는 단지 유용한 점을 공유하고 싶을 것이다. 그래서 아래 스크립트는 Column1과 Column2가 같은지 확인하고, 경우에 따라 비교하기 위해 VARBINARY로 변환을 사용하여 필요하지 않은 경우 제거 할 수 있습니다.

--c1 = Length of Column1
--c2 = Length of Column2

ISNULL(NULLIF(CONVERT(VARBINARY(cl), LTRIM(RTRIM(Column1))),
              CONVERT(VARBINARY(c2), LTRIM(RTRIM(Column2)))),
       NULLIF(CONVERT(VARBINARY(c2), LTRIM(RTRIM(Column2))),
              CONVERT(VARBINARY(c1), LTRIM(RTRIM(Column1))))) IS NULL

IS NOT NULL불완전한 조건을 확인 하기 위해 식 끝을 변경할 수 있습니다 .

이 도움을 바랍니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.