Групповые позиции заказа в комплектах продуктов - PullRequest
0 голосов
/ 29 сентября 2018

Это моя схема:

CREATE TABLE SampleProducts 
(
    ProductId INT,
    Name NVARCHAR(20)
)

INSERT INTO SampleProducts 
VALUES (1, 'Product 1'), (2, 'Product 2'), (3, 'Product 3'),
       (4, 'Product 4')

CREATE TABLE Bundle  
(
    BundleId INT,
    Name NVARCHAR(20)
)

INSERT INTO Bundle 
VALUES (1, 'Bundle 1'), (2, 'Bundle 2')

CREATE TABLE BundleProduct  
(
    BundleId INT,
    ProductId INT
)

INSERT INTO BundleProduct 
VALUES (1, 1), (1, 2), (2, 3), (2, 4)

CREATE TABLE SaleOrder 
(
    OrderId INT,
    OrderNumber NVARCHAR(20)
)

INSERT INTO SaleOrder 
VALUES (1, 'SO0001'), (2, 'SO0002'), (3, 'SO0003')

CREATE TABLE SaleOrderLine 
(
    OrderLineId INT,
    OrderId     INT,
    ProductId   INT
)

INSERT INTO SaleOrderLine 
VALUES (1, 1, 1), (2, 1, 2), (3, 2, 1), 
       (4, 3, 3), (5, 3, 4)

Мне нужно найти заказы, где клиенты покупают продукты, которые могут быть сгруппированы в пакет.Например, для заказа SO0001 продукты 1 и 2 были проданы, этот заказ должен быть в результате.Только в SO0002 был продан продукт 1. SO0003 содержит продукты из Bundle2.Это заданный результат, который мне нужно получить:

Результат

| OrderId | BundleId |
+---------+----------+
|    1    |     1    |
|    3    |     2    |

Как получить результат?

Ответы [ 3 ]

0 голосов
/ 30 сентября 2018

Этот запрос объединяет SaleOrderLines с Bundles для подсчета различных продуктов из каждого SaleOrder, которые содержатся в конкретном Bundle.Если это число является общим количеством продуктов в этом комплекте, у нас есть совпадение:

WITH
  BundleProductCount (BundleID, ProductCount) AS (
    SELECT BundleId, COUNT(ProductId)
    FROM BundleProduct
    GROUP BY BundleId
  ),
  OrderBundleProductCount (OrderId, BundleId, ProductCount) AS (
    SELECT sol.OrderId, bp.BundleId, COUNT(DISTINCT sol.ProductId)
    FROM SaleOrderLine sol
      INNER JOIN BundleProduct bp ON sol.ProductId = bp.ProductId
    GROUP BY sol.OrderId, bp.BundleId
  )
SELECT ob.OrderId, ob.BundleId
FROM OrderBundleProductCount ob
  INNER JOIN BundleProductCount b ON ob.BundleID = b.BundleID
WHERE ob.ProductCount = b.ProductCount;

Добавлено:

Более короткая версия того, что вы придумалиВы уважаете продукты, появляющиеся несколько раз в одном и том же порядке:

SELECT l.OrderId, bp.BundleId
FROM SaleOrderLine l
  INNER JOIN BundleProduct bp ON l.ProductId = bp.ProductId
GROUP BY l.OrderId, bp.BundleId
HAVING COUNT(DISTINCT l.ProductId) = (
    SELECT COUNT(*)
    FROM BundleProduct
    WHERE BundleId = bp.BundleId
    );
0 голосов
/ 30 сентября 2018

Это моя лучшая попытка решить эту проблему:

SELECT o.[OrderId], bp.[BundleId]
FROM [SaleOrder] o
INNER JOIN [SaleOrderLine] l ON l.[OrderId] = o.[OrderId]
INNER JOIN [SampleProducts] p ON p.[ProductId] = l.[ProductId]
INNER JOIN [BundleProduct] bp ON bp.[ProductId] = l.[ProductId]
GROUP BY o.[OrderId], bp.[BundleId]
HAVING COUNT(*) = (
    SELECT COUNT(*)
    FROM [Bundle] b
    INNER JOIN [BundleProduct] bp2 ON bp.[BundleId] = b.[BundleId]
    WHERE bp2.[BundleId] = bp.[BundleId]
    GROUP BY b.[BundleId]
    )

Сначала я присоединяюсь к линиям заказов на продажу с продуктами Bundle, группирую их, а затем подсчитываю их и сравниваю с количеством продуктов в Bundle, еслирезультат равен, это означает, что пакет может быть создан.Идея аналогична решению, предложенному Вольфгангом Кайсом, но без использования общих табличных выражений

*** Обновление

Это новый запрос, удаляющий ненужные объединения.Спасибо @ MatBailie

SELECT l.[OrderId], bp.[BundleId]
FROM [SaleOrderLine] l
INNER JOIN [BundleProduct] bp ON bp.[ProductId] = l.[ProductId]
GROUP BY l.[OrderId], bp.[BundleId]
HAVING COUNT(*) = (
    SELECT COUNT(*)
    FROM [BundleProduct] bp2
    WHERE bp2.[BundleId] = bp.[BundleId]
    GROUP BY bp2.[BundleId]
    )
0 голосов
/ 29 сентября 2018

Row_Number является ключевой функцией здесь.Запрос можно записать в виде:

select distinct
OrderId , 
BundleId
From  
(
select SO.OrderId,B.BundleId , 
ROW_NUMBER() OVER(PARTITION BY SO.OrderId  ORDER BY SO.OrderId ASC) AS Row#     
from SaleOrderLine SOL
join SaleOrder SO on SOL.OrderId = SO.OrderId
join BundleProduct BP on BP.ProductId = SOL.ProductId
join Bundle B on B.BundleId = BP.BundleId
) As Test

where Row# > 1

Полный запрос здесь ..

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