Trả về các hàng trong đó tất cả các giá trị không phải NULL đều bằng nhau


7

Có một cấu trúc T-SQL đơn giản hơn để "tất cả các cột này bằng nhau (NULL bị bỏ qua) trên một hàng" - tôi muốn nói hiệu quả:

WHERE MIN(a, b, c) = MAX(a, b, c) OR COALESCE(a, b, c) IS NULL
  • nó sẽ tương đương với COALESCE của tất cả các hoán vị bằng nhau - nhưng không có hàm MIN / MAX không tổng hợp

Một thay thế cho 3 cột là:

WHERE ( 
COALESCE(a, b, c) = COALESCE(b, c, a) 
AND COALESCE(a, b, c) = COALESCE(c, a, b) 
AND COALESCE(a, b, c) = COALESCE(b, a, c) 
AND COALESCE(a, b, c) = COALESCE(a, c, b) 
AND COALESCE(a, b, c) = COALESCE(c, b, a) 
) 
OR COALESCE(a, b, c) IS NULL

tức là "Tất cả các cột không phải NULL a, b, c phải bằng nhau hoặc tất cả các cột có thể là null"

Rõ ràng việc triển khai PIVOT / UNPIVOT có thể được thực hiện hoặc một tuyên bố CASE phức tạp, nhưng tôi đang tìm kiếm một cái gì đó tương đối đơn giản.

Trong trường hợp này, các cột đều là số nguyên, vì vậy tôi đoán có lẽ có một mẹo toán học mà tôi có thể tìm ra.


Rất nhiều câu trả lời hay, tôi sẽ phải đánh giá chúng trước khi trao giải chấp nhận, xin lỗi.
Cade Roux

Câu trả lời:


8

Cú pháp nhỏ gọn nhất tôi có thể tìm thấy là:

SELECT * 
FROM @T AS t
WHERE EXISTS 
(
    SELECT ISNULL(ISNULL(a, b), c) 
    INTERSECT 
    SELECT ISNULL(ISNULL(b, c), a) 
    INTERSECT 
    SELECT ISNULL(ISNULL(c, a), b)
);

Dựa trên một ý tưởng từ một trong những bài đăng trên blog cũ của tôi mô tả cách sử dụng INTERSECTEXCEPTthay thế các so sánh như a <> b OR (a IS NULL AND b IS NULL)với NOT EXISTS (a INTERSECT b).


5

Bạn có thể thực hiện tổng hợp trên các cột bằng cách sử dụng VALUES(a),(b),(c)hoặc nếu bạn đang sử dụng SQL Server trước năm 2008, bạn có thể thực hiện SELECT a UNION ALL SELECT b UNION ALL SELECT c.

SELECT *
FROM @T
WHERE (SELECT MIN(x) FROM (VALUES(a),(b),(c)) AS T(x)) =
      (SELECT MAX(x) FROM (VALUES(a),(b),(c)) AS T(x)) OR
      COALESCE(a, b, c) IS NULL;

Cập nhật:

Một cái gì đó bởi vẻ bề ngoài của nó sẽ nhanh hơn một chút.

SELECT T.*
FROM @T AS T
CROSS APPLY (
            SELECT MIN(x), MAX(x)
            FROM (VALUES(T.a),(T.b),(T.c)) AS X(x)
            ) AS X(MinValue, MaxValue)
WHERE X.MinValue = X.MaxValue OR
      (X.MinValue IS NULL AND X.MaxValue IS NULL);

5

Một biến thể về câu trả lời của @ Mikael:

SELECT * 
FROM @T
WHERE (SELECT COUNT(DISTINCT x) FROM (VALUES(a),(b),(c)) AS T(x))
      <= 1 ; 

1
SELECT COUNT(DISTINCT columnValue)
FROM(SELECT a AS columnValue
UNION ALL SELECT b
UNION ALL SELECT c
) AS ColumnValues
WHERE columnValue IS NOT NULL

Điều này dễ dàng mở rộng đến hơn ba cột.

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.