SQL Server - найдите всех клиентов, которые разместили два типа заказов - PullRequest
2 голосов
/ 02 апреля 2019

Я пытаюсь получить список всех открытых заказов от клиента, в котором один и тот же клиент использовал один из наших специальных типов оплаты, а также один из наших стандартных вариантов.В частности, те, которые имеют открытые ордера с или предоплатой или 10n30 и хотя бы одним нормальным ордером.Итак, в приведенных ниже таблицах примеров я хотел бы вернуть order_id 1, 3 и 4.

cust_orders                       order_info
+----------+-----------+          +----------+-------------+----------+
| cust_id  | order_id  |          | order_id |  pay_type   |  status  |
+----------+-----------+          +----------+-------------+----------+
|       1  |         1 |          |       1  | standard    | open     |
|       1  |         2 |          |       2  | prepay      | closed   |
|       1  |         3 |          |       3  | prepay      | open     |
|       1  |         4 |          |       4  | 10n30       | open     |
|       2  |         5 |          |       5  | standard    | deferred |
|       2  |         6 |          |       6  | prepay      | open     |
|       3  |         7 |          |       7  | N/A         | deferred |
|       4  |         8 |          |       8  | prepay      | open     |
|       4  |         9 |          |       9  | standard    | closed   |
|       4  |        10 |          |      10  | prepay      | open     |
+----------+-----------+          +----------+-------------+----------+

У меня есть следующий запрос

SELECT *
FROM cust_orders AS co
    LEFT JOIN ( SELECT *
              FROM order_info
              WHERE pay_type IN('prepay', '10n30')
              AND status = 'open' ) AS o1 on o1.order_id = co.order_id
    LEFT JOIN ( SELECT *
              FROM order_info
              WHERE pay_type NOT IN('prepay', '10n30')
              AND status = 'open' ) AS o2 on o2.order_id = co.order_id
WHERE o1.order_id IS NOT NULL
     AND o2.order_id IS NOT NULL
ORDER BY co.order_id DESC;

, но он работает очень медленнои возвращает кучу дубликатов.

Я смотрел на Поиск заказов, которые имеют два продукта, один с конкретной ссылкой, другой с конкретным описанием и ВЫБРАТЬ все заказы с болеечем один предмет и проверьте статус всех предметов , но ни один из них не является тем, что мне нужно


РЕДАКТИРОВАТЬ: Спасибо gjvdkamp за основу для кода ниже;Я изменил их решение для использования в запросе большего размера, и теперь все работает нормально.

SELECT co.*, [other fields]
FROM cust_order AS co
     LEFT JOIN [other tables]
WHERE cust_id IN ( SELECT co.cust_id
                   FROM cust_order AS co
                        LEFT JOIN order_info o on o.order_id = co.order_id
                   WHERE o.status = 'open'
                   GROUP BY co.cust_id
                   HAVING SUM(CASE WHEN o.pay_type IN ('prepay', '10n30') THEN 1 ELSE 0 END) > 0 
                      AND SUM(CASE WHEN (o.pay_type NOT IN ('prepay', '10n30') OR o.pay_type IS NULL) THEN 1 ELSE 0 END) > 0)

Ответы [ 2 ]

2 голосов
/ 02 апреля 2019

Здесь бы хорошо работал «поворотный круг»:

select cust_id,
       sum(case when pay_type = 'normal'             then 1 else 0 end) as NormalCount,
       sum(case when pay_type in ('prepay', '10n30') then 1 else 0 end) as OtherCount
from   cust_order co 
       inner join order o on co.order_id = o.order_id 
where  o.status = 'open'
       and o.pay_type in ('normal','prepay','10n30')
group by cust_id
having NormalCount> 0 and 
       OtherCount > 0

Для этого потребуется только одно объединение (объединение, если у вас есть правильные индексы), а затем его объединение. Не знаю статистику по вашей таблице заказов, но добавил оператор where на pay_type для хорошей оценки. Это было бы трудно побить скорость.

Редактировать: убрал оператор with, поскольку он даже не нужен

1 голос
/ 02 апреля 2019

Я думаю, что некоторые оконные функции делают свое дело:

select o.*
from (select o.*,
             sum(case when o.pay_type in ('prepay', '10n30') then 1 else 0 end) over (partition by co.cust_id) as num_special,
             sum(case when o.pay_type in ('standard') then 1 else 0 end) over (partition by co.cust_id) as num_standard
      from cust_orders co join
           order_info o
           on co.orderid = o.order_id
      where o.status = 'open' 
     ) o
where num_standard > 0 and
      num_special > 0;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...