【问题标题】:SQL join where all joined meet conditionSQL 连接,所有连接都满足条件
【发布时间】:2019-04-29 10:55:33
【问题描述】:

我需要一些关于 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];

我现在需要这个来只拉动他们的 ALL 声明处于指定状态的客户,但我不知道该怎么做。如何让所有索赔都具有此状态描述的客户?我可以为此提供指导或解决方案吗?

这是相关的架构; Claims Table

Contacts Table

Clients Table

这是返回的查询图像,其中客户的任何索赔都处于状态; Current results

【问题讨论】:

  • 您好,感谢您使用 Stack Overflow。上面的描述很好。以我们可以用来构建模式的格式提供一些示例数据会很有用。根据样本数据获得所需的输出也会很有用

标签: sql sql-server join


【解决方案1】:

类似(完全未经测试的代码!):

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]

应该做的伎俩。

【讨论】:

  • 谢谢 - 此解决方案耗时 4 秒,而 @Joel 解决方案耗时 17 秒,但返回的客户却是其他状态的索赔
【解决方案2】:

解决方法是使用排除原则。您编写一个查询以获取所有具有至少一次状态的客户端。好消息:这部分已经完成 :) 接下来您编写查询以查找具有任何其他状态的客户端。一旦你有这两个查询,你把它们放在一起以从第一组中排除第二组。您可以通过多种方式执行此操作:NOT EXISTS() 表达式、NOT IN() 表达式、排除连接或the EXCEPT keyword 都可以工作。

我个人最喜欢排除连接,但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 是一个下标。

【讨论】:

  • 感谢您的解决方案和课程 :) 我正在查看并试一试。尽快通知您
  • 效果很好。谢谢。我打算将此解决方案与@James 解决方案进行比较以提高速度
  • 我不确定 James 的解决方案是否真的能满足您的要求。
  • @James 没有“成功”。排除耗时 4 秒,而非 17 秒。感谢您提供详细信息
猜你喜欢
  • 1970-01-01
  • 2022-07-19
  • 2019-03-14
  • 1970-01-01
  • 2013-07-23
  • 2017-11-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多