У меня есть 3 таблицы с именами «Транзакции», «Клиенты» и «Билеты». Каждый билет имеет категорию (Театр, Кино или Концерт). Я хочу найти имя человека, который сделал больше всего покупок для каждой категории:
Например:
Category | Name | Purchases Theater George 5 Cinema Tom 12 Cinema Mary 12 Concert John 7
WITH PurchasesSum AS (
SELECT Category,Customers.Name,COUNT(Transactions.Customer_ID) AS Purchases,
RANK() OVER (ORDER BY COUNT(Transactions.Customer_ID) DESC) AS Rank
FROM Transactions
INNER JOIN Customers
ON Transactions.Customer_ID= Customers.ID
INNER JOIN Tickets
ON Transactions.Ticket_num = Tickets.Ticket_num
GROUP BY Name,Category
)
SELECT Name, Purchases,Category
FROM PurchasesSum
ORDER BY Category ASC;
Пока я дошел до этого момента, но он возвращает их всех
Например:
Category | Name | Purchases Cinema Tom 12 Cinema Mary 12 Cinema John 3 Concert John 7 Concert Tom 1 Theater George 5 Theater Mary 2


Вы очень близко. Расширьте предложение OVER в rank() до PARTITION BY category, чтобы ранг относился к категории. Затем поместите предложение WHERE во внешнюю фильтрацию запросов для ранга один.
WITH
purchasessum
AS
(
SELECT category,
customers.name,
count(transactions.customer_id) purchases,
rank() OVER (PARTITION BY category
ORDER BY count(transactions.customer_id) DESC) rank
FROM transactions
INNER JOIN customers
ON transactions.customer_id = customers.id
INNER JOIN tickets
ON transactions.ticket_num = tickets.ticket_num
GROUP BY name,
category
)
SELECT name,
purchases,
category
FROM purchasessum
WHERE rank = 1
ORDER BY category ASC;
В Postges я рекомендую использовать DISTINCT ON. Это не только более лаконично, но часто и быстрее:
SELECT DISTINCT ON (Category) Category, c.Name,
COUNT(*) AS Purchases,
FROM Transactions t JOIN
Customers c
ON t.Customer_ID = c.ID JOIN
Tickets ti
ON t.Ticket_num = ti.Ticket_num
GROUP BY Category, c.Name
ORDER BY Category, COUNT(*) DESC;