Pourquoi COALESCE dans une sous-requête renvoie NULL?

15

Compte tenu de ce schéma:

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

Si j'utilise COALESCE dans une sous-requête, elle renvoie 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                |
+----+---------------------+---------------------+

Cependant, s'il est placé en dehors de la sous-requête:

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

Pourquoi le premier sous - requête ne retourne pas: t1.DateTest?

http://rextester.com/CNDOO40877

McNets
la source
3
EXCELLENTE utilisation d'une table de démonstration et d'une requête de repro, soit dit en passant. Je n'allais pas poster de réponse, mais ensuite je suis allé, "Il a mis tout ce travail dans la question, le moins que je pouvais faire est de mettre un peu de travail dans une réponse, hahaha."
Brent Ozar
Salut @BrentOzar, merci pour votre réponse détaillée, elle est limpide.
McNets

Réponses:

16

Les éléments de la sélection ne sont renvoyés que si des lignes sont renvoyées dans l'instruction FROM.

Tout d'abord, réfléchissons conceptuellement.

La requête 1 est comme:

"Allez trouver toutes les Ferrari dans votre garage. Pour chaque Ferrari, donnez-moi le numéro de plaque d'immatriculation, ou si elle n'a pas de numéro de plaque, donnez-moi" AUCUN FERRARIS TROUVÉ. ""

La requête reviendrait sans lignes - car il n'y avait pas de Ferrari dans le garage. (Au moins, aucune rangée n'a été trouvée dans mon propre garage.)

La requête 2 est différente:

"Allez au garage. SI vous trouvez une plaque d'immatriculation sur une Ferrari, donnez-moi ça - sinon, donnez-moi 'PAS DE FERRARIS TROUVÉ.'"

C'est pourquoi la fusion doit être en dehors de l'opération de recherche: vous en avez besoin même s'il n'y a pas de lignes dans le jeu de résultats.

Examinons maintenant votre requête.

Je vais supprimer la sous-requête seule et je vais coder en dur les valeurs pour l'une des lignes où vous voulez que COALESCE fonctionne, mais cela ne peut pas:

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

Dans la clause WHERE, j'ai codé en dur Id = 1 et DateTest> '2017-02-03 00: 00: 00.000'. Lorsque cette requête s'exécute, elle ne renvoie aucun résultat:

Aucune Ferrari trouvée

C'est pourquoi le COALESCE ne fonctionne pas: il n'y avait pas de rangées dans cet ensemble de résultats et pas de Ferrari dans votre garage. Maîtrisez ce concept, et vous aurez des Ferrari dans votre ... attendez une minute ... J'ai maîtrisé ce concept, et il n'y a pas de Ferrari dans mon garage ...

Brent Ozar
la source
3
Hahaha, regardez attentivement, êtes-vous sûr qu'il n'y a pas de Modène 360 là-bas?
McNets
3
@McNets Je devrais probablement vérifier à nouveau juste pour être sûr.
Brent Ozar