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

Mal*_*ist 35 sql t-sql sql-server

我有一个查询,我想作为子查询运行,将返回一组FK.有了它们,我想只返回具有匹配键的行.

子查询:

SELECT ID 
FROM tblTenantTransCode 
WHERE
    tblTenantTransCode.CheckbookCode = 
      (SELECT ID FROM tblCheckbookCode WHERE Description = 'Rent Income')
Run Code Online (Sandbox Code Playgroud)

这将返回所有具有与租金收入匹配的支票簿代码的交易代码

现在我想选择所有事务,其事务代码与子查询中返回的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'))
Run Code Online (Sandbox Code Playgroud)

表:

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  

spe*_*593 66

要回答有关使用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是它清楚地表明我们不感兴趣从子查询中的表中返回任何表达式.它用于逻辑地将子查询与外部查询分开,其方式与a JOIN不相同.

使用的另一个优点EXISTS是,如果我们改为使用a,则避免返回可能(可能)返回的重复行JOIN.

一个EXISTS谓语可用于测试的子表的任何相关行的存在,而不需要加入.例如,以下查询返回一组包含至少一个关联line_item的所有订单:

    SELECT o.*
      FROM order o
     WHERE EXISTS
           ( SELECT 1
               FROM line_item li
              WHERE li.order_id = o.id
           )

请注意,子查询不需要查找所有匹配的行项,它只需要找到一行以满足条件.(如果我们将此查询编写为a 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'
                    )
           )

最重要的是,在给定所有可能的条件集的情况下,查询应返回正确的结果集,满足指定的要求.

在此处作为答案呈现的一些查询返回请求的结果集,或者如果它们发生,则它们偶然发生.如果我们预先假设有关数据的某些内容,则某些查询将起作用,因此某些列是UNIQUENOT NULL.

性能差异

有时,带有EXISTS谓词的查询的执行效果不如带有谓词JOININ谓词的查询 .在某些情况下,它可能表现更好.(对于EXISTS谓词,子查询只需找到一行满足条件,而不是找到所有匹配的行,如a所要求的那样JOIN.)

各种查询选项的性能最好通过观察来衡量.

  • "EXISTS也清楚地表明你对[内表中的行" - 也称为"半连接"不感兴趣,并且可能会在查询计划中显示出来.(我已经看到SQL Server使用"左反半连接"节点,这在第一次有点令人吃惊)三种方法的性能大致相同,在不同的数据库平台和数据分布之间变化很大.一如既往,看看查询计划,不要猜. (3认同)

Aus*_*nen 5

您正在描述内部联接.

select tc.id 
from tblTenantTransCode tc 
   inner join tblCheckbookCode cc on tc.CheckbookCode = cc.CheckbookCode
Run Code Online (Sandbox Code Playgroud)

编辑:它仍然是一个内部联接.我认为还没有任何理由使用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'
Run Code Online (Sandbox Code Playgroud)

编辑:如果必须使用EXISTS谓词来解决此问题,请参阅@ spencer7953的答案.然而,从我所看到的,上面的解决方案更简单,并且基于"子查询"为您工作的事实存在唯一性的假设(如果该表中没有唯一性,则不会100%的时间).我也在说

现在我想选择所有事务,其事务代码与子查询中返回的ID 匹配

在我的回答中.如果请求是这样的:

现在我想在任何事务代码与子查询中返回的ID匹配选择All Transcations .

我会使用EXISTS查看子表中是否存在任何事务代码,并根据需要返回每一行或没有.

  • Eric,是什么让你觉得"加入比IN条款更有效率."?事实并非如此. (2认同)
  • 我应该详细说明:IN子句与子查询.子查询,尤其是当它们使用父查询中的元素时,会触发每一行,从而使其效率极低.IN(1,2,3)完全没有效率.执行IN(SELECT ID from a WHERE A.ID = SOME_PARENT_ID)是非常低效的. (2认同)