#sql #sql-server #tsql
Вопрос:
Допустим, у меня есть три таблицы для управления покупками в моем интернет-магазине:
- Товары: со столбцами ID, Название, Цена
- Клиенты: с идентификатором столбца, именем
- Покупки: со столбцами ProductID, CustomerID, Дата покупки
Теперь, как бы я мог получить продукты, приобретенные более чем N
разными клиентами?
Я попробовал следующее в пробной версии SQL Server 2019, но при подсчете я получаю синтаксическую ошибку.
SELECT ProductID, CustomerID, COUNT(*) as C
FROM Purchases
GROUP BY ProductID, CustomerID
HAVING C > 100
ORDER BY C DESC
Еще лучше, как бы я мог получить продукты, приобретенные более чем N
разными клиентами в течение 30-дневного периода?
Спасибо за любую помощь и/или указания.
Комментарии:
1. Ваша текущая схема не поддерживает это, вы не сохраняете временные метки покупок. В данном сценарии нет способа отфильтровать покупки по диапазону данных.
2. Пожалуйста, опубликуйте точное сообщение об ошибке
Ответ №1:
С вашим текущим запросом вы просто подсчитываете, как часто каждый клиент покупал каждый продукт, потому что вы группируетесь по сочетанию productid
и customerid
. Кроме того, вы не можете ссылаться на псевдоним столбца для количества в HAVING
ORDER BY
предложении или
Попробуйте это
declare @purchasedatelower datetime = dateadd(day, -30, getdate())
declare @purchasedateupper datetime = getdate()
declare @distinctcustomers int = 100
select productid, count(distinct customerid) as customercount
from purchases
where purchasedate between @purchasedatelower and @purchasedateupper
group by productid
having count (distinct customerid) >= @distinctcustomers
order by count(distinct customerid) desc
Это вернет все продукты, которые были куплены по крайней мере 100 различными клиентами за последние 30 дней, вместе с определенным количеством клиентов.
Комментарии:
1. Это делает свое дело. И большое спасибо за ваше объяснение!
2. Я уже сделал это. И я получаю сообщение «Спасибо за отзыв! Вам нужно не менее 15 репутации, чтобы проголосовать, но ваши отзывы были записаны».
3. @KeineUrsache вы можете принять ответ, нажав на галочку. Чего вы не можете сделать (пока), так это озвучить ответ, нажав на стрелку вверх.
Ответ №2:
Попробуйте заказать их по COUNT()
SELECT ProductID, CustomerID
FROM Purchases
GROUP BY ProductID, CustomerID
HAVING COUNT(*) > 100
ORDER BY COUNT(*) DESC
Комментарии:
1. Это лучше, но я также получаю предметы, приобретенные несколько раз только одним клиентом.
Ответ №3:
Теперь, как бы я мог получить продукты, приобретенные более чем N различными клиентами?
Вы бы использовали COUNT(DISTINCT)
:
SELECT ProductID, COUNT(DISTINCT CustomerID) as num_customers
FROM Purchases
GROUP BY ProductID
HAVING COUNT(DISTINCT CustomerID) > 100
ORDER BY COUNT(DISTINCT CustomerID) DESC;
Если вы имеете в виду определенный период, добавьте WHERE
предложение перед GROUP BY
.
Ответ №4:
DECLARE @Popularity int = 1
DECLARE @MonthsAgo int = 1
SELECT p.ProductId, p.ProductName, pc.CustomersDistinct
FROM (
-- Sub-query to compute the aggregate.
-- Count the number of distinct customers that purchased each product.
SELECT ProductId, COUNT(DISTINCT CustomerId) AS CustomersDistinct
FROM Purchases
WHERE PurchaseDate >= DATEADD(MONTH, -@MonthsAgo, CURRENT_TIMESTAMP)
GROUP BY ProductId
HAVING COUNT(DISTINCT CustomerId) > @Popularity
) AS pc
-- Now do JOINs to look up helpful values for the final SELECT list.
INNER JOIN Products p ON pc.ProductId = p.ProductId
ORDER BY 3 DESC