Por que COALESCE em uma subconsulta retorna NULL?

15

Dado este esquema:

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 eu usar COALESCE dentro de uma subconsulta, ele retornará 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                |
+----+---------------------+---------------------+

No entanto, se for colocado fora da subconsulta:

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

Por que a primeira subconsulta não retorna t1.DateTest:?

http://rextester.com/CNDOO40877

McNets
fonte
3
EXCELENTE uso de uma tabela de demonstração e uma consulta de reprodução, a propósito. Eu não ia postar uma resposta, mas depois eu disse: "Ele colocou todo esse trabalho em questão, o mínimo que eu poderia fazer é colocar algum trabalho em resposta, hahaha".
Brent Ozar
Olá @BrentOzar, obrigado pela resposta detalhada, é claro.
McNets

Respostas:

16

As coisas na seleção são retornadas apenas se houver linhas retornadas na instrução FROM.

Primeiro, vamos pensar conceitualmente.

A consulta 1 é como:

"Vá encontrar todos os Ferraris em sua garagem. Para cada Ferrari, me dê o número da placa, ou, se não tiver uma placa, me dê 'NENHUM FERRARIS ENCONTROU'".

A consulta voltava sem linhas - porque não havia uma Ferrari na garagem. (Pelo menos, não foram encontradas linhas na minha própria garagem.)

A consulta 2 é diferente:

"Vá para a garagem. Se você encontrar uma placa de carro em uma Ferrari, me dê isso - caso contrário, me dê 'SEM FERRARIS ENCONTRADO'".

É por isso que a coalescência precisa estar fora da operação de pesquisa: você precisa que aconteça mesmo quando não houver linhas no conjunto de resultados.

Agora, vejamos sua consulta.

Vou remover a subconsulta por conta própria e codificar valores para uma das linhas em que você deseja que o COALESCE funcione, mas não pode:

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

Na cláusula WHERE, codifiquei Id = 1 e DateTest> '2017-02-03 00: 00: 00.000'. Quando essa consulta é executada, ela não retorna resultados:

Nenhum Ferraris encontrado

É por isso que o COALESCE não funciona: não havia linhas neste conjunto de resultados e nenhum Ferraris em sua garagem. Domine esse conceito, e você terá Ferraris no seu ... espere um minuto ... Eu dominei esse conceito, e não há Ferraris na minha garagem ...

Brent Ozar
fonte
3
Hahaha, olhe atentamente, você tem certeza de que não há nenhum 360 Modena lá?
McNets
3
@ McNets Eu provavelmente deveria ir verificar novamente apenas por segurança.
Brent Ozar 23/02