Dlaczego COALESCE w podzapytaniu zwraca NULL?

15

Biorąc pod uwagę ten schemat:

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

Jeśli użyję COALESCE w podzapytaniu, zwraca NULL.

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

Jeśli jednak zostanie umieszczony poza podzapytaniem:

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

Dlaczego pierwszy podzapytanie nie wraca: t1.DateTest?

http://rextester.com/CNDOO40877

McNets
źródło
3
Nawiasem mówiąc, DOSKONAŁE wykorzystanie tabeli demo i zapytania repro. Nie zamierzałem publikować odpowiedzi, ale potem powiedziałem: „Zadał całą tę pracę pytaniu, przynajmniej mogłem zrobić trochę pracy w odpowiedzi, hahaha”.
Brent Ozar
Cześć @BrentOzar, dzięki za szczegółową odpowiedź, jest krystalicznie czysty.
McNets

Odpowiedzi:

16

Rzeczy w zaznaczeniu są zwracane tylko wtedy, gdy w instrukcji FROM zwracane są wiersze.

Po pierwsze, pomyślmy o tym koncepcyjnie.

Zapytanie 1 jest jak:

„Idź znaleźć wszystkie Ferrari w swoim garażu. Dla każdego Ferrari podaj mi numer rejestracyjny, a jeśli nie ma numeru rejestracyjnego, daj mi„ NIE ZNALEZIONO FERRARIS ”.

Zapytanie wróci bez żadnych wierszy - ponieważ w garażu nie było Ferrari. (Przynajmniej w moim garażu nie znaleziono żadnych wierszy).

Zapytanie 2 jest inne:

„Idź do garażu. JEŻELI znajdziesz tablicę rejestracyjną na Ferrari, daj mi to - w przeciwnym razie daj mi„ NIE ZNALEZIONO FERRARIS ”.

Dlatego koalescencja musi znajdować się poza operacją wyszukiwania: musisz to zrobić, nawet jeśli w zestawie wyników nie ma wierszy.

Teraz spójrzmy na twoje zapytanie.

Wybiorę podzapytanie na własną rękę i idę do twardego kodu wartości dla jednego z wierszy, w których chcesz, aby działał COALESCE, ale nie może:

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

W klauzuli WHERE mam zakodowane na stałe Id = 1 i DateTest> '2017-02-03 00: 00: 00.000'. Po uruchomieniu tego zapytania nie zwraca żadnych wyników:

Nie znaleziono Ferraris

Właśnie dlatego COALESCE nie działa: w tym zestawie wyników nie było wierszy i nie ma Ferrari w garażu. Opanuj tę koncepcję, a będziesz mieć Ferrarisa w swoim ... poczekaj chwilę ... Opanowałem tę koncepcję, aw moim garażu nie ma Ferrarisa ...

Brent Ozar
źródło
3
Hahaha, spójrz uważnie, czy jesteś pewien, że nie ma tam żadnej Modeny 360 ?
McNets
3
@McNets Prawdopodobnie powinienem ponownie sprawdzić, aby być bezpiecznym.
Brent Ozar