¿Por qué COALESCE dentro de una subconsulta devuelve 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');

Si uso COALESCE dentro de una subconsulta, devuelve 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                |
+----+---------------------+---------------------+

Sin embargo, si se coloca fuera de la 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 qué la primera subconsulta no regresa t1.DateTest:?

http://rextester.com/CNDOO40877


3
EXCELENTE uso de una tabla de demostración y una consulta de repro, por cierto. No iba a publicar una respuesta, pero luego dije: "Puso todo este trabajo en la pregunta, lo menos que pude hacer fue poner algo de trabajo en una respuesta, jajaja".
Brent Ozar

Hola @BrentOzar, gracias por tu respuesta detallada, es claro como el cristal.
McNets

Respuestas:


16

Las cosas en la selección se devuelven solo si hay filas devueltas en la instrucción FROM.

Primero, pensemos en esto conceptualmente.

La consulta 1 es como:

"Ve a buscar todos los Ferrari en tu garaje. Para cada Ferrari, dame el número de placa, o si no tiene un número de placa, dame 'NO SE ENCONTRARON FERRARIS'".

La consulta volvería sin filas, porque no había un Ferrari en el garaje. (Al menos, no se encontraron filas en mi propio garaje).

La consulta 2 es diferente:

"Ve al garaje. SI encuentras una matrícula en un Ferrari, dame eso; de lo contrario, dame 'NO SE ENCUENTRAN FERRARIS'".

Es por eso que la fusión debe estar fuera de la operación de búsqueda: necesita que suceda incluso cuando no haya filas en el conjunto de resultados.

Ahora, veamos su consulta.

Voy a sacar la subconsulta por su cuenta, y voy a codificar valores para una de las filas donde desea que funcione COALESCE, pero no puede:

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

En la cláusula WHERE, he codificado Id = 1 y DateTest> '2017-02-03 00: 00: 00.000'. Cuando se ejecuta esta consulta, no devuelve resultados:

No se encontraron ferraris

Es por eso que COALESCE no funciona: no había filas en este conjunto de resultados, ni Ferraris en su garaje. Domina ese concepto, y tendrás Ferraris en tu ... espera un minuto ... He dominado ese concepto, y no hay Ferraris en mi garaje ...


3
Jajaja, mira con cuidado, ¿estás seguro de que no hay ninguna Módena 360 allí?
McNets

3
@McNets Probablemente debería volver a verificar solo para estar seguro.
Brent Ozar
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.