繁体   English   中英

如何使用T-SQL的Exists关键字?

[英]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似乎有很多讨论(与原始问题的答案有关)。

这些构造是替代的,但不是必需的。 查询可以返回所需的结果集,而无需使用INJOIN 可以通过使用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'
                    )
           )

最重要的是,查询应返回正确的结果集,该结果集应满足所有可能的条件集,并满足指定的要求。

此处以答案形式出现的某些查询不会返回请求的结果集,或者如果返回的话,它们恰巧是偶然返回的。 如果我们预先假设一些有关数据的查询,则某些查询将起作用,例如,某些UNIQUENOT NULL

性能差异

有时,带有EXISTS谓词的查询的性能不如带有JOININ谓词的查询。 在某些情况下,它的性能可能更好。 (使用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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM