[英]How do I use T-SQL's Exists keyword?
我有一个查询要作为子查询运行,该查询将返回一组FK。 对于它们,我只想返回具有匹配键的行。
SELECT ID
FROM tblTenantTransCode
WHERE
tblTenantTransCode.CheckbookCode =
(SELECT ID FROM tblCheckbookCode WHERE Description = 'Rent Income')
这将返回所有具有与租金收入匹配的支票簿代码的交易代码
现在,我要选择所有事务的事务代码与子查询中返回的ID匹配的所有事务。 到目前为止,我已经了解了,但是SQL Server抱怨语法错误。 我怎样才能做到这一点?
SELECT *
FROM tblTransaction
WHERE
tblTransaction.TransactionCode IN
(SELECT ID FROM tblTenantTransCode
WHERE tblTenantTransCode.CheckbookCode =
(SELECT ID FROM tblCheckbookCode WHERE Description = 'Rent Income'))
tblCheckbookCode ID Description Other Info tblTenantTransCode ID CheckbookCode <-- fk we're looking for in the tblCheckbookCode. We're selecting only checkbook codes that have the Description 'Rent Income' Other Info tblTransactions ID TransactionCode <-- fk to tenant transaction code. We're looking for an ID that is returned in the above query/join
为了回答有关使用EXISTS关键字的问题,下面是一个示例查询,该查询基于您问题中当前给出的查询,使用EXISTS谓词。
SELECT t.* FROM tblTransaction t WHERE EXISTS ( SELECT 1 FROM tblTenantTransCode ttc JOIN tblCheckbookCode cc ON (cc.ID = ttc.CheckbookCode AND cc.Description='Rent Income') WHERE ttc.ID = t.TransactionCode )
额外细节:
我们都知道,有各种各样的SQL语句将返回满足指定要求的结果集。 这些查询的观察性能可能会有所不同。 性能尤其取决于DBMS,优化器模式,查询计划和统计信息(行数和数据值分布)。
EXISTS
优点之一在于,很明显,我们对从子查询表中返回任何表达式都不感兴趣。 它用于以逻辑上的方式将子查询与外部查询分开,而JOIN
则没有。
使用EXISTS
另一个优点是避免了返回重复的行,如果我们改为使用JOIN
,这些行将(可能)返回。
EXISTS
谓词可用于测试子表中是否存在任何相关行,而无需联接。 例如,以下查询返回一组至少具有一个关联的line_item的所有订单:
SELECT o.* FROM order o WHERE EXISTS ( SELECT 1 FROM line_item li WHERE li.order_id = o.id )
请注意,子查询不需要查找所有匹配的订单项,只需要查找一行即可满足条件。 (如果我们将此查询编写为JOIN
,则每当订单中有一个以上订单项时,我们都会返回重复的行。)
NOT EXISTS
谓词也很有用,例如,返回没有任何关联的line_items的一组订单。
SELECT o.* FROM order o WHERE NOT EXISTS ( SELECT 1 FROM line_item li WHERE li.order_id = o.id )
当然, NOT EXISTS
只是一种选择。 可以使用OUTER连接和IS NULL测试获得等效的结果集(假设我们从line_item表中至少有一个不是NOT NULL的表达式)
SELECT o.* FROM order o LEFT JOIN line_item li ON (li.order_id = o.id) WHERE li.id IS NULL
关于需要使用IN
谓词或需要使用JOIN
似乎有很多讨论(与原始问题的答案有关)。
这些构造是替代的,但不是必需的。 查询可以返回所需的结果集,而无需使用IN
和JOIN
。 可以通过使用EXISTS
谓词的查询返回结果集。 (请注意,OP问题的标题确实询问了如何使用EXISTS
关键字。)
这是另一个替代查询(这不是我的首选),但是返回的结果集确实满足指定的要求:
SELECT t.* FROM tblTransaction t WHERE EXISTS ( SELECT 1 FROM tblTenantTransCode ttc WHERE ttc.ID = t.TransactionCode AND EXISTS ( SELECT 1 FROM tblCheckbookCode cc WHERE cc.ID = ttc.CheckbookCode AND cc.Description = 'Rent Income' ) )
最重要的是,查询应返回正确的结果集,该结果集应满足所有可能的条件集,并满足指定的要求。
此处以答案形式出现的某些查询不会返回请求的结果集,或者如果返回的话,它们恰巧是偶然返回的。 如果我们预先假设一些有关数据的查询,则某些查询将起作用,例如,某些UNIQUE
和NOT NULL
。
性能差异
有时,带有EXISTS
谓词的查询的性能不如带有JOIN
或IN
谓词的查询。 在某些情况下,它的性能可能更好。 (使用EXISTS
谓词,子查询只需要查找满足条件的一行,而不必查找JOIN
所需的所有匹配行。)
各种查询选项的性能最好通过观察来衡量。
您正在描述内部联接。
select tc.id
from tblTenantTransCode tc
inner join tblCheckbookCode cc on tc.CheckbookCode = cc.CheckbookCode
编辑:这仍然是一个内部联接。 我看不出有任何理由要使用IN子句。
select *
from tblTransaction t
inner join tblTenantTransCode tc on tc.id = t.TransactionCode
inner join tblCheckbookCode cc on cc.id = tc.CheckbookCode
where cc.description = 'Rent Income'
编辑:如果必须使用EXISTS谓词来解决此问题,请参见@ spencer7953的答案。 但是,据我所知,上面的解决方案比较简单,并且基于“子查询”为您工作这一事实(因此如果该表中没有唯一性,则不会100%的时间),就存在唯一性假设)。 我也在讲
现在,我要选择所有事务的事务代码与子查询中返回的ID 匹配的所有事务
在我的回答中。 如果请求是这样的话:
现在, 当任何交易代码与子查询中返回的ID匹配时,我想选择“所有交易”。
我将使用EXISTS来查看子表中是否存在任何交易代码,并酌情返回每一行或不返回任何行。
给定您的完整查询,此查询将使您可以使用单个联接到达所需的位置。
联接会过滤出没有“ Rent Income”交易代码的任何交易。 它将从第一个表中获取所有记录,构建第二个表的子集(该WHERE子句限制了这些记录),然后过滤第一个表,其中那些表对联接条件进行数学运算。
SELECT
t.*
FROM
tblTransaction t
INNER JOIN tblTenantTransCode c ON
t.TransactionCode = c.ID
INNER JOIN tblCheckbookCode chk ON
c.CheckbookCode = chk.ID
WHERE
chk.Description = 'Rent Income'
编辑:另一个注意事项:避免使用SELECT *-始终指定列。 编辑注意事项:我错过了三张桌子。 更正! 谢谢,斯潘塞!
尝试这个:
SELECT
tblTenantTransCode.ID
FROM tblCheckbookCode
INNER JOIN tblTenantTransCode ON tblCheckbookCode.ID=tblTenantTransCode.CheckbookCode
WHERE tblCheckbookCode.Description = 'Rent Income'
确保您索引tblCheckbookCode.Description
。
您需要使用“ IN”子句:
select id from tblTenantTransCode
where tblTenantTransCode.CheckbookCode in
(select id from tblCheckbookCode
where description = 'rent income')
内部连接可能是更好的解决方案...
select ttc.id from tblTenantTransCode as ttc
inner join tblCheckbookCode as tcc
on ttc.CheckBookId = tcc.id
where tcc.description = 'rent income'
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.