为什么子查询中的COALESCE返回NULL?


15

给定此架构:

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

如果我在子查询中使用COALESCE,它将返回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                |
+----+---------------------+---------------------+

但是,如果将其放置在子查询之外:

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

为什么第一个子查询不返回:t1.DateTest

http://rextester.com/CNDOO40877


3
顺便说一句,演示表和repro查询的出色使用。我本来不想发布答案,但后来我说:“他把所有这些工作都放在了问题上,我至少能做的就是把一些工作放在答案上,哈哈哈。”
布伦特·奥扎尔

嗨,@ BrentOzar,谢谢您的详细回答,这很清楚。
McNets '17

Answers:


16

仅当FROM语句中返回行时,才返回select中的内容。

首先,让我们从概念上考虑一下。

查询1类似于:

“去车库里找到所有的法拉利车。给每个法拉利车牌号,给我,如果没有车牌号,给我'没有找到法拉利车。'”

该查询将无行返回-因为车库中没有法拉利。(至少,在我自己的车库中没有发现任何行。)

查询2不同:

“去车库。如果在法拉利上找到车牌,给我,否则给我'没有发现法拉利'。”

这就是为什么合并必须在搜索操作之外的原因:即使结果集中没有行,也需要进行合并。

现在,让我们看看您的查询。

我将自行删除子查询,并且将硬编码其中要COALESCE工作的行之一的值,但是它不能:

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子句中,我对Id = 1进行了硬编码,并且DateTest>'2017-02-03 00:00:00.000'。该查询运行时,不返回任何结果:

找不到法拉利

这就是为什么COALESCE不起作用的原因:该结果集中没有行,并且您的车库中没有法拉利。掌握了这个概念,您将拥有法拉利……等一下……我已经掌握了这个概念,而且我的车库里也没有法拉利……


3
哈哈哈,仔细看,您确定那里没有360摩德纳吗?
McNets '17

3
@McNets我可能应该再次检查一下以确保安全。
布伦特·奥扎尔
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.