Как получить первое имя для каждой категории из таблицы? PostgreSQL

У меня есть 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
ReactJs | Supabase | Добавление данных в базу данных
ReactJs | Supabase | Добавление данных в базу данных
Это и есть ваш редактор таблиц в supabase.👇
Понимание Python и переход к SQL
Понимание Python и переход к SQL
Перед нами лабораторная работа по BloodOath:
0
0
26
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 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;

Другие вопросы по теме