Bir alt sorgudaki COALESCE neden NULL döndürüyor?


15

Bu şema göz önüne alındığında:

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

Bir alt sorgu içinde COALESCE kullanırsanız, NULL döndürür.

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

Ancak, alt sorgunun dışına yerleştirilirse:

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

İlk alt sorgu neden geri dönmüyor t1.DateTest?

http://rextester.com/CNDOO40877


3
Bu arada, bir demo tablosu ve repro sorgusunun MÜKEMMEL kullanımı. Ben bir cevap göndermeyecektim, ama sonra gittim, "Bütün bu çalışmaları soruya soktu, yapabildiğim en az şey bir cevaba biraz iş koymak, hahaha."
Brent Ozar

Merhaba @BrentOzar, detaylı cevabınız için teşekkürler, kristal berraklığında.
McNets

Yanıtlar:


16

Seçimdeki şeyler yalnızca FROM deyiminde döndürülen satırlar varsa döndürülür.

İlk olarak, kavramsal olarak düşünelim.

Sorgu 1 şöyle:

"Git garajında ​​tüm Ferraris'i bul. Her Ferrari için bana plaka numarasını ver yoksa plaka numarası yoksa bana 'FERRARİS BULUNAMADI' ver."

Sorgu satır olmadan geri gelecekti - çünkü garajda bir Ferrari yoktu. (En azından kendi garajımda hiç satır bulunamadı.)

Sorgu 2 farklıdır:

"Garaja git. Eğer Ferrari'de bir plaka bulursan, bana şunu ver - yoksa bana 'FERRARİS BULUNAMADI' ver."

Bu nedenle birleşmenin arama işleminin dışında olması gerekir: sonuç kümesinde hiç satır olmasa bile gerçekleşmesi gerekir.

Şimdi sorgunuza bakalım.

Alt sorguyu tek başına çıkaracağım ve COALESCE'ın çalışmasını istediğiniz satırlardan biri için sabit kod değerlerine gideceğim, ancak yapamaz:

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

WHERE yan tümcesinde, sabit kodlanmış Id = 1 ve DateTest> '2017-02-03 00: 00: 00.000' kodlarını kullandım. Bu sorgu çalıştırıldığında hiçbir sonuç döndürmez:

Ferraris bulunamadı

İşte bu yüzden COALESCE çalışmıyor: Bu sonuç kümesinde hiç satır ve garajınızda Ferraris yoktu. Bu konsepte hakim olursanız, Ferraris'inizde ... bir dakika bekleyin ... Bu konsepte hakim oldum ve garajımda Ferraris yok ...


3
Hahaha, dikkatle bak, orada 360 Modena olmadığından emin misin ?
McNets

3
@McNets Muhtemelen tekrar güvende olmak için tekrar kontrol etmeliyim.
Brent Ozar
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.