Perché COALESCE all'interno di una sottoquery restituisce NULL?


15

Dato questo schema:

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

Se uso COALESCE in una sottoquery, restituisce 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                |
+----+---------------------+---------------------+

Tuttavia, se viene posizionato all'esterno della sottoquery:

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

Perché la prima sottoquery non restituisce: t1.DateTest?

http://rextester.com/CNDOO40877


3
A proposito, utilizzo ECCELLENTE di una tabella demo e di una query di riprogrammazione. Non avevo intenzione di pubblicare una risposta, ma poi ho detto "Ha messo tutto questo lavoro nella domanda, il minimo che potevo fare è mettere un po 'di lavoro in una risposta, hahaha".
Brent Ozar,

Ciao @BrentOzar, grazie per la tua risposta dettagliata, è cristallino.
McNets,

Risposte:


16

Le cose nella selezione vengono restituite solo se ci sono righe restituite nell'istruzione FROM.

Innanzitutto, pensiamolo concettualmente.

La query 1 è come:

"Vai a trovare tutte le Ferrari nel tuo garage. Per ogni Ferrari, dammi il numero di targa o, se non ha un numero di targa, dammi 'NO FERRARIS FOUND.'"

La domanda sarebbe tornata senza righe, perché non c'era una Ferrari nel garage. (Almeno, non sono state trovate file nel mio garage.)

La query 2 è diversa:

"Vai in garage. SE trovi una targa su una Ferrari, dammi che, altrimenti, dammi" NESSUN FERRARIS TROVATO. ""

Ecco perché la coalizione deve essere al di fuori dell'operazione di ricerca: è necessario che accada anche quando non ci sono righe nel set di risultati.

Ora diamo un'occhiata alla tua domanda.

Prenderò la subquery da sola e userò i valori hard-code per una delle righe in cui vuoi far funzionare COALESCE, ma non può:

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

Nella clausola WHERE, ho codificato Id = 1 e DateTest> '2017-02-03 00: 00: 00.000'. Quando viene eseguita questa query, non restituisce risultati:

Nessuna Ferrari trovata

Ecco perché la COALESCE non funziona: non c'erano righe in questo set di risultati e Ferrari nel tuo garage. Padroneggia questo concetto e avrai Ferrari nel tuo ... aspetta un minuto ... Ho imparato quel concetto e non ci sono Ferrari nel mio garage ...


3
Hahaha, guarda attentamente, sei sicuro che non ci sia 360 Modena lì?
McNets,

3
@McNets Probabilmente dovrei andare a controllare di nuovo solo per sicurezza.
Brent Ozar,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.