Rückgabe von Zeilen, in denen alle Nicht-NULL-Werte gleich sind

7

Gibt es ein einfacheres T-SQL-Konstrukt für "alle diese Spalten müssen in einer Zeile gleich sein (NULL-Werte ignoriert)" - effektiv möchte ich sagen:

WHERE MIN(a, b, c) = MAX(a, b, c) OR COALESCE(a, b, c) IS NULL
  • Dies wäre das Äquivalent der COALESCEs aller Permutationen, um gleich zu sein - es gibt jedoch keine nicht aggregierende MIN / MAX-Funktion

Eine Alternative für 3 Spalten ist:

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

dh "Alle Nicht-NULL-Spalten a, b, c müssen gleich sein oder alle Spalten können null sein"

Natürlich könnte eine PIVOT / UNPIVOT-Implementierung oder eine komplexe CASE-Anweisung durchgeführt werden, aber ich suche etwas relativ Einfaches.

In diesem Fall sind die Spalten alle Ganzzahlen, daher gibt es wahrscheinlich einen mathematischen Trick, den ich herausfinden könnte.

Cade Roux
quelle
So viele gute Antworten, ich muss sie bewerten, bevor ich die Annahme erteile, sorry.
Cade Roux

Antworten:

8

Die kompakteste Syntax, die ich finden kann, ist:

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

Basierend auf einer Idee von einem meiner alten Blog - Posts , das beschreibt , wie verwenden INTERSECTund EXCEPTVergleiche zu ersetzen wie a <> b OR (a IS NULL AND b IS NULL)mit NOT EXISTS (a INTERSECT b).

Paul White 9
quelle
5

Sie können das Aggregieren über Spalten mit VALUES(a),(b),(c)oder, wenn Sie SQL Server vor 2008 verwenden, durchführen 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;

Aktualisieren:

Etwas, das anscheinend etwas schneller sein sollte.

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);
Mikael Eriksson
quelle
5

Eine Variation von @ Mikaels Antwort:

SELECT * 
FROM @T
WHERE (SELECT COUNT(DISTINCT x) FROM (VALUES(a),(b),(c)) AS T(x))
      <= 1 ; 
ypercubeᵀᴹ
quelle
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

Dies kann leicht auf mehr als drei Spalten erweitert werden.

AK
quelle