簡體   English   中英

所有聯接均滿足條件的SQL連接

[英]SQL join where all joined meet condition

我需要一些有關SQL查詢的幫助。

我有桌子:客戶| 索賠| 狀態| 往來

我有一個查詢來查找所有客戶及其聯系方式,其中任何索償均為指定狀態:

SELECT
  clients.id           AS "Client Ref"
 ,claims.clientclaimid AS "Claim Number"
 ,Contacts.PhoneHome   AS "Mobile"
 ,statuses.description AS Status
FROM
  dbo.claims
LEFT JOIN
  statuses
    ON
    dbo.claims.statusID = statuses.ID
LEFT JOIN
  clients
    ON
    dbo.claims.clientid = clients.id
LEFT JOIN
  contacts
    ON
    clients.contactid = Contacts.id
WHERE
  statuses.description = 'client - pack sent to customer'
  AND (DATEADD(MM, -@joinedpremonthsago, GETDATE()) > clients.DateJoined)
  AND clients.DateJoined > 01 / 01 / 2012
  AND claims.active = 1
ORDER BY
  [Client Ref]
 ,[Claim Number];

現在,我只需要將所有聲明都處於指定狀態的客戶拉出,但是我不知道該怎么做。 如何獲得所有聲明都具有此狀態描述的客戶? 我可以為此提供指導或解決方案嗎?

這是相關的架構; 索償表

在此處輸入圖片說明

聯系人表

在此處輸入圖片說明

客戶表

在此處輸入圖片說明

這是查詢返回的圖像,其中客戶的任何索賠都處於狀態。 當前結果

在此處輸入圖片說明

解決的辦法是使用排除原則。 您編寫查詢以獲取所有確實具有該狀態的所有客戶端至少一次。 好消息:這部分已經完成了:)接下來,編寫查詢以查找具有其他任何狀態的客戶端。 擁有兩個查詢后,將它們組合在一起即可從第一組中排除第二組。 您可以通過幾種方式執行此操作: NOT EXISTS()表達式, NOT IN()表達式,排除EXCEPTEXCEPT關鍵字都可以起作用。

就個人而言,我對排除連接最為滿意,但NOT EXISTS()更為常見,並且往往表現得更好:

select cli.id as "Client Ref", cla.clientclaimid as "Claim Number", co.PhoneHome as "Mobile"

from dbo.claims cla

inner join statuses s on cla.statusID = s.ID 
inner join clients cli on cla.clientid = cli.id
left join contacts co on cli.contactid = co.id

where s.description = 'client - pack sent to customer'
    and (DateAdd(MM, -@joinedpremonthsago, GetDate()) >  cli.DateJoined) 
    and cli.DateJoined > 01/01/2012
    and cla.active=1

    and NOT EXISTS ( 
        select 1 
        from clients cli0
        inner join claims cla0 on cla0.clientid = cli0.id
        inner join statuses s0 on s0.ID = cla0.statusID
        WHERE cli0.ID = cli.ID
           AND s0.description <> 'client - pack sent to customer'
    )

order by [Client Ref], [Claim Number]

排除聯接版本:

select cli.id as "Client Ref", cla.clientclaimid as "Claim Number", co.PhoneHome as "Mobile"

from dbo.claims cla

inner join statuses s on cla.statusID = s.ID AND s.description = 'client - pack sent to customer'
inner join clients cli on cla.clientid = cli.id
left join contacts co on cli.contactid = co.id
-- the "JOIN" part of an exclusion join
left join statuses s2 on cla.statusID = s2.ID AND s2.description <> 'client - pack sent to customer'

where (DateAdd(MM, -@joinedpremonthsago, GetDate()) >  cli.DateJoined) 
    and cli.DateJoined > 01/01/2012
    and cla.active=1

    -- the "EXCLUSION" part of an exclusion join
    and s2.ID IS NULL

order by [Client Ref], [Claim Number]

請注意,我是如何選擇“ inner而不是“ left來進行某些原始連接的。 在WHERE子句中使用這些表的字段的方式已經使它們有效地成為內部聯接。 對聯接類型誠實可以幫助您發現錯誤,並可以使Sql Server建立更好的執行計划。

還要注意,我從SELECT子句結果中刪除了狀態,因為現在要求已隱含了這一點。

最后,請注意如何將表別名添加到查詢中。 最好在查詢中始終使用表別名。 如果您想在單個查詢中多次引用同一張表,則絕對有必要避免歧義,就像我們在此處的兩個示例中一樣。 按照慣例,這些別名通常是表名的縮寫,甚至是單個字母。 因此,此查詢中的cliclient縮寫,我使用了3個完整字符,以便將其與claims區分開。 內部查詢中使用cli0表示“客戶素數” ...認為0就像是下標。

類似於(完全未經測試的代碼!):

select  clients.id as "Client Ref", claims.clientclaimid as "Claim Number",
        Contacts.PhoneHome as "Mobile",statuses.description as Status
from dbo.claims
left join clients on dbo.claims.clientid = clients.id
left join contacts on clients.contactid = contacts.id

where (DateAdd(MM, -@joinedpremonthsago, GetDate()) >  clients.DateJoined) 
    and clients.DateJoined > 01/01/2012
    and claims.active=1
    and dbo.claims.clientID in (
       select dbo.claims.clientID 
       from dbo.claims
       left join statuses on dbo.claims.statusID = statuses.ID
       where statuses.description = 'client - pack sent to customer'
    )

order by [Client Ref], [Claim Number]

應該做到的。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM