SELECT列表中的词法范围?

时间:2013-08-22 14:21:16

标签: sql sql-server tsql

考虑以下问题:

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]

它将为NULL返回new_pos_stop,而不是从子查询中抓取h.pos_stop中的值。

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

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

2 个答案:

答案 0 :(得分:1)

原因很简单:

仅当使用级别ISNULL()的查询返回任何结果时,才能使用

ISNULL()。 在这两个示例中,外部查询都返回在相关子查询中使用Id and associate_number的行。

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

在第二个中,ISNULL()处于子查询级别,因此如果没有行满足子查询WHERE条件,则外部查询中的列值将为NULL,表示未返回任何行通过子查询。请注意,如果存在符合WHERE ih.pos_start == NULL条件的子查询行,ISNULL()将按预期工作。

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

答案 1 :(得分:1)

这不是一个范围问题。查询正在按预期工作。考虑第一个版本:

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

子查询可以返回{em>两种方式NULL。第一个是ih.pos_startNULL时。第二个是子查询根本不返回任何行。在标量子查询的上下文中,没有行被视为NULL

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

现在考虑第二种情况:

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

子查询中的isnull() 。所以,这只处理上面的第一个案例。

您获得了NULL个值,因为子查询没有返回任何行。