Warum gibt COALESCE in einer Unterabfrage NULL zurück?

15

In Anbetracht dieses Schemas:

CREATE TABLE #TEST_COALESCE
(
    Id int NOT NULL,
    DateTest datetime NOT NULL,
    PRIMARY KEY (Id, DateTest)
);

INSERT INTO #TEST_COALESCE VALUES
(1, '20170201'),
(1, '20170202'),
(1, '20170203'),
(2, '20170204'),
(2, '20170205'),
(2, '20170206');

Wenn ich COALESCE in einer Unterabfrage verwende, wird NULL zurückgegeben.

SELECT  t1.Id, t1.DateTest,
        (SELECT TOP 1 COALESCE(t2.DateTest, t1.DateTest)
         FROM         #TEST_COALESCE t2
         WHERE        t2.Id = t1.Id
         AND          t2.DateTest > t1.DateTest
         ORDER BY     t2.Id, t2.DateTest) NextDate
FROM    #TEST_COALESCE t1;

+----+---------------------+---------------------+
| Id | DateTest            | NextDate            |
+----+---------------------+---------------------+
| 1  | 01.02.2017 00:00:00 | 02.02.2017 00:00:00 |
| 1  | 02.02.2017 00:00:00 | 03.02.2017 00:00:00 |
| 1  | 03.02.2017 00:00:00 | NULL                |
| 2  | 04.02.2017 00:00:00 | 05.02.2017 00:00:00 |
| 2  | 05.02.2017 00:00:00 | 06.02.2017 00:00:00 |
| 2  | 06.02.2017 00:00:00 | NULL                |
+----+---------------------+---------------------+

Wenn es sich jedoch außerhalb der Unterabfrage befindet:

SELECT  t1.Id, t1.DateTest,
        COALESCE((SELECT TOP 1 t2.DateTest
                 FROM         #TEST_COALESCE t2
                 WHERE        t2.Id = t1.Id
                 AND          t2.DateTest > t1.DateTest
                 ORDER BY     t2.Id, t2.DateTest), t1.DateTest) NextDate
FROM    #TEST_COALESCE t1;

+----+---------------------+---------------------+
| Id | DateTest            | NextDate            |
+----+---------------------+---------------------+
| 1  | 01.02.2017 00:00:00 | 02.02.2017 00:00:00 |
| 1  | 02.02.2017 00:00:00 | 03.02.2017 00:00:00 |
| 1  | 03.02.2017 00:00:00 | 03.02.2017 00:00:00 |
| 2  | 04.02.2017 00:00:00 | 05.02.2017 00:00:00 |
| 2  | 05.02.2017 00:00:00 | 06.02.2017 00:00:00 |
| 2  | 06.02.2017 00:00:00 | 06.02.2017 00:00:00 |
+----+---------------------+---------------------+

Warum die erste Unterabfrage nicht zurück: t1.DateTest?

http://rextester.com/CNDOO40877

McNets
quelle
3
Übrigens AUSGEZEICHNETE Verwendung einer Demo-Tabelle und einer Repro-Abfrage. Ich wollte keine Antwort posten, aber dann fuhr ich fort: "Er hat all diese Arbeit in die Frage gesteckt. Das Mindeste, was ich tun kann, ist, etwas Arbeit in eine Antwort zu stecken, hahaha."
Brent Ozar
Hallo @BrentOzar, danke für deine ausführliche Antwort, es ist glasklar.
McNets

Antworten:

16

Dinge in der Auswahl werden nur zurückgegeben, wenn Zeilen in der FROM-Anweisung zurückgegeben werden.

Lassen Sie uns zunächst konzeptionell darüber nachdenken.

Abfrage 1 ist wie folgt:

"Gehen Sie und finden Sie alle Ferrari in Ihrer Garage. Geben Sie mir für jeden Ferrari das Kennzeichen oder, falls er kein Kennzeichen hat," NO FERRARIS FOUND "."

Die Abfrage würde ohne Zeilen zurückkommen - weil kein Ferrari in der Garage war. (Zumindest wurden in meiner Garage keine Zeilen gefunden.)

Abfrage 2 ist anders:

"Geh in die Garage. Wenn du ein Nummernschild auf einem Ferrari findest, gib mir das - sonst gib mir 'NO FERRARIS FOUND'."

Aus diesem Grund muss sich die Vereinigung außerhalb der Suchoperation befinden: Sie müssen dies auch dann tun, wenn die Ergebnismenge keine Zeilen enthält.

Schauen wir uns nun Ihre Anfrage an.

Ich werde die Unterabfrage alleine ausführen und Werte für eine der Zeilen, in denen COALESCE funktionieren soll, hart codieren, aber es kann nicht:

SELECT TOP 1 COALESCE(t2.DateTest, 'NO FERRARIS FOUND')
     FROM         #TEST_COALESCE t2
     WHERE        t2.Id = 1
     AND          t2.DateTest > '2017-02-03 00:00:00.000'
     ORDER BY     t2.Id, t2.DateTest

In der WHERE-Klausel habe ich Id = 1 und DateTest> '2017-02-03 00: 00: 00.000' fest codiert. Wenn diese Abfrage ausgeführt wird, werden keine Ergebnisse zurückgegeben:

Keine Ferraris gefunden

Deshalb funktioniert die COALESCE nicht: In dieser Ergebnismenge waren keine Zeilen und in Ihrer Garage keine Ferraris. Beherrsche dieses Konzept und du wirst Ferraris in deiner ... Moment mal ... Ich habe dieses Konzept gemeistert und es gibt keine Ferraris in meiner Garage ...

Brent Ozar
quelle
3
Hahaha, sieh genau hin, bist du sicher, dass es dort kein 360 Modena gibt?
McNets
3
@McNets Ich sollte wahrscheinlich nochmal nachsehen, nur um sicher zu gehen.
Brent Ozar