考虑以下问题:
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
子句中利用ih
和WHERE
(即当前正在选择的行)的值,但不能在SELECT
列表中使用?
简而言之,显示 SELECT
列表没有词汇范围(松散地使用该术语),我是否正确?换句话说,SELECT
列表只能 利用直接 FROM
子句中的内容。
答案 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_start
为NULL
时。第二个是子查询根本不返回任何行。在标量子查询的上下文中,没有行被视为NULL
。
在这两种情况下,值都将替换为h.pos_stop
。
现在考虑第二种情况:
(select isnull(. . ., h.pos_stop) . . .) as new_pos_stop
子查询中的isnull()
。所以,这只处理上面的第一个案例。
您获得了NULL
个值,因为子查询没有返回任何行。