[英]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()
表达式,排除EXCEPT
或EXCEPT
关键字都可以起作用。
就个人而言,我对排除连接最为满意,但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子句结果中删除了状态,因为现在要求已隐含了这一点。
最后,请注意如何将表别名添加到查询中。 最好在查询中始终使用表别名。 如果您想在单个查询中多次引用同一张表,则绝对有必要避免歧义,就像我们在此处的两个示例中一样。 按照惯例,这些别名通常是表名的缩写,甚至是单个字母。 因此,此查询中的cli
是client
缩写,我使用了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.