0

考虑以下查询:

SELECT dgc.Id, h.[identity], h.associate_number, h.pos_start, h.pos_stop,
    ISNULL((
        SELECT DATEADD(DAY, -1, ih.pos_start)
        FROM #hr_data_dgc ih
        WHERE ih.associate_number = h.associate_number AND
            ih.Id = (dgc.Id - 1)
    ), h.pos_stop) AS new_pos_stop
FROM #hr_data h
    JOIN #hr_data_dgc dgc ON dgc.[identity] = h.[identity]

并特别注意针对该字段ISNULL的子查询结果所利用的语句。new_pos_stop如果子查询返回,这将按预期工作NULL

现在,如果我要稍微更改该查询:

SELECT dgc.Id, h.[identity], h.associate_number, h.pos_start, h.pos_stop,
    (
        SELECT ISNULL(DATEADD(DAY, -1, ih.pos_start), h.pos_stop)
        FROM #hr_data_dgc ih
        WHERE ih.associate_number = h.associate_number AND
            ih.Id = (dgc.Id - 1)
    ) AS new_pos_stop
FROM #hr_data h
    JOIN #hr_data_dgc dgc ON dgc.[identity] = h.[identity]

它将返回NULLfor而不是从子查询new_pos_stop中获取值。h.pos_stop

这是我不明白的。我能够在子句中利用hand的值ih(即当前选择的行),WHERE但不能在SELECT列表中?

简而言之,该列表似乎SELECT没有词法范围(松散地使用该术语),我对此是否正确?换句话说,SELECT列表只能利用直接 FROM子句中的内容。

4

2 回答 2

1

这样做的原因是简单的:

ISNULL()只有在使用级别查询ISNULL()返回任何结果时才能使用。在这两个示例中,外部查询都会返回Id and associate_number您在相关子查询中使用的行。

在第一个示例ISNULL()中是在外部查询级别。因此,对于子查询不返回结果(或它们是)的每个外部查询行,将放置NULL第二个参数。ISNULL()

第二个ISNULL()是在子查询级别,因此如果没有行满足子查询WHERE条件,则外部查询中的列值将NULL意味着子查询没有返回任何行。请注意,如果存在满足WHERE条件的子查询行ih.pos_start == NULL,ISNULL()将按您的预期工作。

希望解释是可以理解的:)

于 2013-08-22T14:50:26.013 回答
1

这不是范围界定问题。查询完全按应有的方式工作。考虑第一个版本:

isnull((select DATEADD(DAY, -1, ih.pos_start). . ), h.pos_stop) AS new_pos_stop

子查询有两种NULL返回方式。第一个是什么ih.pos_start时候NULL。第二个是子查询根本不返回任何行。在标量子查询的上下文中,没有行被视为NULL.

在这两种情况下,值都将替换为h.pos_stop

现在考虑第二种情况:

(select isnull(. . ., h.pos_stop) . . .) as new_pos_stop

位于isnull()子查询内。所以,这只处理上面的第一种情况。

您正在获取NULL值,因为子查询没有返回任何行。

于 2013-08-22T14:53:10.750 回答