2014-12-18 3 views
2

Я пытаюсь написать запрос, который вытаскивает лучших 5 клиентов по количеству всех продуктов, которые они приобрели. Нет проблем. Но, кроме того, мне нужно найти продукт, который был самым популярным для каждого из этих 5 клиентов.Пытается найти самый популярный продукт

Я думаю, что могу сделать это, посмотрев, какой продукт они купили больше всего (так что количество productID является максимальным количеством), но я не совсем уверен, как добраться до идентификатора продукта. Есть идеи? Неужели я все это делаю неправильно? Благодаря!

select top 5 c.CustomerID, sum(sod.orderqty) AS 'Amount Purchased', 
max(sod.orderqty) AS 'Most Purchased' 
from Sales.Customer c 
inner join Sales.SalesOrderHeader soh on soh.CustomerID = c.CustomerID 
inner join Sales.SalesOrderDetail sod on sod.SalesOrderID = soh.SalesOrderID 
inner join Production.Product p on p.ProductID = sod.ProductID 
group by c.CustomerID 
order by 'Amount Purchased' desc 

Я попробовал запрос ниже, но по некоторым причинам, в том числе p.name в группе, полностью скидывает макс. Например, в этом запросе, «Наиболее продаваемое» должно быть 20, но он показывает, как 18

select top 5 soh.CustomerID, sum(sod.orderqty) AS 'Amount Purchased' 
, max(sod.orderqty) AS 'Most Purchased', p.name 
from Sales.SalesOrderHeader soh 
inner join Sales.SalesOrderDetail sod on sod.SalesOrderID = soh.SalesOrderID 
inner join Production.Product p on p.ProductID = sod.ProductID 
where soh.CustomerID = 29705 
group by soh.CustomerID, p.name 
order by 'Amount Purchased' desc 

ответ

1

Мы можем сделать это в два этапа. Я использую SQL Server 2008.

В первой найти топ 5 клиентов, как вы делали:

WITH 
CTE_TopCustomers 
AS 
(
    select top (5) 
     c.CustomerID 
     , sum(sod.orderqty) AS 'Amount Purchased' 
    from 
     Sales.Customer c 
     inner join Sales.SalesOrderHeader soh on soh.CustomerID = c.CustomerID 
     inner join Sales.SalesOrderDetail sod on sod.SalesOrderID = soh.SalesOrderID 
     inner join Production.Product p on p.ProductID = sod.ProductID 
    group by 
     c.CustomerID 
    order by 'Amount Purchased' desc 
) 

Тогда для каждого из этих клиентов найти самый популярный продукт. См. Подзапрос в CROSS APPLY. «Самый популярный» здесь означает продукт, который клиент купил больше всего. Скажем, если клиент купил 10 единиц некоторого продукта с ID=1 на один день и 20 единиц того же продукта с ID=1 на следующий день, сумма будет равна 30. Если тот же клиент купил 25 единиц другого продукта с ID=2 все на одном день, то самым популярным продуктом для этого клиента будет тот, у которого есть ID=1 и 30 единиц.

Если вы хотите выбрать продукт с ID=2 как наиболее популярными в этом примере, изменить SUM к MAX внутри CROSS APPLY.

SELECT 
    CTE_TopCustomers.CustomerID 
    ,CTE_TopCustomers.[Amount Purchased] 
    ,CTE_Products.ProductID 
    ,CTE_Products.ProductName 
    ,CTE_Products.SumCustomerProductQty 
FROM 
    CTE_TopCustomers 
    CROSS APPLY 
    (
     SELECT TOP (1) 
      p.ProductID 
      ,p.name AS ProductName 
      ,SUM(sod.orderqty) AS SumCustomerProductQty 
     FROM 
      Sales.SalesOrderHeader soh on soh.CustomerID = CTE_TopCustomers.CustomerID 
      inner join Sales.SalesOrderDetail sod on sod.SalesOrderID = soh.SalesOrderID 
      inner join Production.Product p on p.ProductID = sod.ProductID 
     GROUP BY 
      p.ProductID 
      ,p.name 
     ORDER BY SumCustomerProductQty DESC 
    ) AS CTE_Products 
ORDER BY [Amount Purchased] DESC; 

Для окончательного запроса просто поместите оба блока кода вместе.

+0

Я получаю ошибку в кресте применительно к «FROM Sales.SalesOrderHeader soh on soh.customerID = CTE_TopCustomers.CustomerID». Он говорит о некорректном синтаксисе рядом с «on». Ничто из того, что я делаю, не исправляет это ... – Michelle

+0

Выяснил это. Это выглядит фантастически, спасибо! – Michelle

+0

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

0

ли промежуточное агрегации с помощью продукта (который является вторым-следующего макс.):

select top 5 CustomerId, sum(AmountPurchased) as AmountPurchased, 
     max(AmountPurchased) as maxAmountPurchased, 
     max(case when seqnum = 1 then productId end) as MostPurchased 
from (select c.CustomerID, p.ProductId, sum(sod.orderqty) AS AmountPurchased, 
      row_number() over (partition by c.CustomerId order by sum(sod.orderqty) desc) as seqnum 
     from Sales.Customer c inner join 
      Sales.SalesOrderHeader soh 
      on soh.CustomerID = c.CustomerID inner join 
      Sales.SalesOrderDetail sod 
      on sod.SalesOrderID = soh.SalesOrderID inner join 
      Production.Product p 
      on p.ProductID = sod.ProductID 
     group by c.CustomerID, ProductId 
    ) cp 
group by CustomerId 
order by AmountPurchased desc; 

Обратите внимание, что это немного отличается от вашего запроса в отношении максимальной суммы. Эта версия обеспечивает максимальный уровень на уровне всего продукта. Вы можете получить свою версию, используя max() в подзапросе, но это похоже на то, что вы действительно можете захотеть.

+0

Хм, я пробовал это, но цифры, похоже, не срабатывают правильно. Посмотрев на таблицу, max (orderqty) для 1 клиента составляет 20 (поэтому он заказал 20 из продуктаID = 1), но при выполнении запроса он показывает, что он заказал 180. – Michelle

+0

@Michelle. , , В этом случае ваши объединения, вероятно, будут умножать строки, объединив их в двух разных измерениях. Вам нужно исправить соединения, чтобы получить то, что вы хотите. –