簡體   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