【发布时间】:2019-05-15 23:38:06
【问题描述】:
我正在尝试准确了解 Exists 的工作原理,因此我制作了这个快速临时表来尝试了解它。
Drop Table #mytesttable
create table #mytesttable (edate date, num decimal(4,0), stat varchar(8),etype varchar(12))
insert into #mytesttable
values ('20180401',1,'E','A/W'),
('20180101',1,'E','A/W'),
('20180701',1,'E','A/W'),
('20181001',1,'E','A/W'),
('20190101',1,'E','A'),
('20190301',1,'I','NULL'),
('20190101',2,'E','A'),
('20190301',2,'E','A'),
('20180901',2,'E','A'),
('20190101',3,'E','NULL'),
('20190301',3,'I','NULL'),
('20180901',3,'I','NULL')
在执行下面的查询时,我得到了三行返回,而我预计只有 1 行。
Select *
From #mytesttable
Where edate = '20190101'
and stat = 'E'
and exists(Select *
From #mytesttable sub
Where sub.num = num
and sub.etype = 'A/W'
and sub.edate < '20190101')
结果:
edate num stat etype
2019-01-01 1 E A
2019-01-01 2 E A
2019-01-01 3 E NULL
当我在顶部查询中使用表的全名来引用我匹配的存在语句中的列名时,我得到了我期望的结果。
Select *
From #mytesttable
Where edate = '20190101'
and stat = 'E'
and exists(Select *
From #mytesttable sub
Where sub.num = #mytesttable.num
and sub.etype = 'A/W'
and sub.edate < '20190101')
结果(正确):
edate num stat etype
2019-01-01 1 E A
exists 语句也因此感到困惑,并认为它与 #mytesttable 中的 num 匹配。也就是说,是不是这样看的:
#mytesttable inner join #mytesttable
on num = num
一旦计算结果为 True,它甚至都不查看 Where 子句?如果有人能对此有所了解,那就太棒了。
【问题讨论】:
-
限定所有列引用;最佳实践是为每个表引用分配一个 unique 别名,然后使用唯一别名限定列引用。 (即使您不需要,它也将使任何未来的读者更清楚意图。)例如,为最外层的表引用分配一个别名。
t,然后限定存在子查询sub.num = t.num中的引用。 (我们很清楚......这不是 EXISTS 的问题,而是 SQL 如何解析列引用的问题,首先查看最内层/最近的 FROM 子句,然后再查看外部查询) -
@spencer7593 感谢您的澄清。我认为通过在存在语句中为表起别名,它会阻止“num”在那里解析名称引用。我错了。
-
sub别名和使用sub.限定列引用都很好。这没什么不好。问题只是不合格的列引用。而这个问题是我们推荐模式的原因之一:“为每个表引用分配唯一的表别名”和“限定所有列引用”
标签: sql sql-server tsql subquery exists