So sánh các Cột có thể chứa NULLS - có cách nào thanh lịch hơn không?


16

Tôi biết rằng bạn không thể so sánh một giá trị với NULL và mong đợi một kết quả mà không cần thêm một cái gì đó như trong đoạn mã sau ...

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) 

Câu hỏi của tôi là:

Có cách nào thanh lịch hơn để kiểm tra các giá trị thay đổi trên hai bảng trong đó một bảng có thể là null không?

Giải pháp cần phải làm việc thống nhất trên các loại dữ liệu.

Đây là mã để thiết lập các bảng thử nghiệm ...

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)

Câu trả lời:


24

Bạn có thể sử dụng phương pháp này từ bài viết của Paul White Các kế hoạch truy vấn không có giấy tờ: So sánh bình đẳng

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

Điều này thật tuyệt, tôi đã thử nghiệm nó và nó dường như hành xử chính xác như tôi cần. Cảm ơn rất nhiều.
GWR

1
Drat nó bạn đánh tôi với nó! Mặc dù tôi phải thú nhận rằng bạn đã dạy tôi phương pháp này. Nó thật đẹp. :)
ErikE 16/03 '

Martin, bạn có đang sử dụng phương pháp này để so sánh các bảng quá lớn cho So sánh dữ liệu không?
AK

3

SQL chuẩn, được hỗ trợ trong SQL Server 2005 và tốt hơn:

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

Đây là một cách tiếp cận toàn cầu vì vậy tôi đã không viết lại một truy vấn đã sửa từ câu hỏi. Tôi chỉ muốn chia sẻ một điểm hữu ích có thể giúp ích, vì vậy, tập lệnh bên dưới sẽ kiểm tra xem Cột 1 và Cột 2 có bằng nhau hay không, Ngoài ra còn sử dụng Chuyển đổi thành VARBINARY để so sánh trong trường hợp nhạy cảm và bạn có thể xóa nó nếu không cần thiết.

--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

Bạn có thể thay đổi kết thúc biểu thức thành IS NOT NULL kiểm tra điều kiện không bằng nhau.

Hy vọng điều này giúp đỡ.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.