SQL-соединение, где все соединенные отвечают условию - PullRequest
0 голосов
/ 27 ноября 2018

Мне нужна небольшая помощь для запроса 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 их заявок в указанном состоянии, но я не знаю, как это сделать.Как я могу получить клиентов, у которых все заявки имеют это описание статуса?Могу ли я получить рекомендации или решения для этого?

Вот соответствующая схема; Таблица требований

enter image description here

Таблица контактов

enter image description here

Таблица клиентов

enter image description here

Вот изображение запроса, возвращающего, где ЛЮБОЙ из клиентапретензии в статусе; Текущие результаты

enter image description here

Ответы [ 2 ]

0 голосов
/ 27 ноября 2018

Решение заключается в использовании принципа исключения.Вы пишете запрос, чтобы получить всех клиентов, которые имеют статус хотя бы один раз.Хорошие новости: эта часть уже выполнена :) Затем вы пишете запрос, чтобы найти клиентов, которые имеют любой другой статус.Когда у вас есть оба запроса, вы объединяете их, чтобы исключить второй набор из первого.Вы можете сделать это несколькими способами: выражение NOT EXISTS(), выражение NOT IN(), исключающее соединение или ключевое слово 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 было индексом.

0 голосов
/ 27 ноября 2018

Что-то вроде (полностью непроверенный код!):

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]

Нужно сделать свое дело.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...