Mengapa COALESCE dalam subquery mengembalikan NULL?

15

Dengan skema ini:

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

Jika saya menggunakan COALESCE dalam sebuah subquery, ia mengembalikan 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                |
+----+---------------------+---------------------+

Namun, jika ditempatkan di luar subquery:

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

Mengapa subquery pertama tidak kembali: t1.DateTest?

http://rextester.com/CNDOO40877

McNets
sumber
3
Omong-omong, penggunaan tabel demo dan permintaan repro yang sangat baik. Saya tidak akan mengirim jawaban, tetapi kemudian saya pergi, "Dia memasukkan semua pekerjaan ini ke dalam pertanyaan, yang paling bisa saya lakukan adalah memasukkan beberapa pekerjaan ke dalam jawaban, hahaha."
Brent Ozar
Hai @ BrentOzar, terima kasih atas jawaban terinci Anda, sangat jelas.
McNets

Jawaban:

16

Hal-hal dalam pilih dikembalikan hanya jika ada baris yang dikembalikan dalam pernyataan FROM.

Pertama, mari kita pikirkan secara konseptual.

Kueri 1 seperti:

"Pergilah temukan semua Ferraris di garasimu. Untuk setiap Ferrari, berikan aku nomor plat, atau jika tidak punya nomor plat, beri aku 'TANPA FERRARIS DITEMUKAN.'"

Permintaan akan kembali tanpa baris - karena tidak ada Ferrari di garasi. (Setidaknya, tidak ada baris yang ditemukan di garasi saya sendiri.)

Kueri 2 berbeda:

"Pergilah ke garasi. JIKA kamu menemukan plat di Ferrari, berikan padaku - kalau tidak, beri aku 'TANPA FERRARIS DITEMUKAN.'"

Itulah mengapa gabungan harus berada di luar operasi pencarian: Anda memerlukannya terjadi bahkan ketika tidak ada baris di set hasil.

Sekarang, mari kita lihat kueri Anda.

Saya akan mengambil subquery sendiri, dan saya akan nilai hard-code untuk salah satu baris di mana Anda ingin COALESCE bekerja, tetapi tidak bisa:

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

Dalam klausa WHERE, saya telah mengode-keras Id = 1 dan DateTest> '2017-02-03 00: 00: 00.000'. Ketika kueri ini berjalan, ia tidak mengembalikan hasil:

Tidak ada Ferraris ditemukan

Itu sebabnya COALESCE tidak berfungsi: tidak ada baris dalam rangkaian hasil ini, dan tidak ada Ferraris di garasi Anda. Kuasai konsep itu, dan Anda akan memiliki Ferraris di ... tunggu sebentar ... Saya sudah menguasai konsep itu, dan tidak ada Ferraris di garasi saya ...

Brent Ozar
sumber
3
Hahaha, perhatikan baik-baik, apakah Anda yakin tidak ada Modena 360 di sana?
McNets
3
@ McNets saya mungkin harus memeriksa lagi hanya untuk aman.
Brent Ozar