Postgres通过排名获得顶级帐户的销售额

时间:2017-08-01 11:03:51

标签: sql postgresql filtering ranking

我有以下表格:

Account (id, name)
Solution (id, name)
Sales (solution_id, account_id, month, year, amount)

我需要计算特定时期内每个帐户的月销售额:

SELECT
  to_char(make_date(sales.year, sales.month, 1), 'YYYY-MM') AS period,
  acc.id AS account_id,
  acc.name AS account_name,
  COALESCE(SUM(sales.net_sales), 0) AS amount
FROM
  (SELECT * 
   FROM sales
   WHERE make_date(year, month, 1) >= FROM_DATE
     AND make_date(year, month, 1) <= TO_DATE) sales
  INNER JOIN account acc.id = sales.account_id
GROUP BY sales.year, sales.month
ORDER BY sales.year, sales.month ASC

我现在可以在以下范围内计算总销售额:

SELECT
  to_char(make_date(sales.year, sales.month, 1), 'YYYY-MM') AS period,
  acc.id AS account_id,
  acc.name AS account_name,
  COALESCE(SUM(sales.net_sales), 0) AS amount
FROM
  (SELECT *, COALESCE(SUM(net_sales) OVER (PARTITION BY client_id), 0) AS total
   FROM sales
   WHERE make_date(year, month, 1) >= FROM_DATE
     AND make_date(year, month, 1) <= TO_DATE) sales
  INNER JOIN account acc.id = sales.account_id
GROUP BY sales.year, sales.month
ORDER BY sales.year, sales.month ASC

是否有办法对总销售额进行排名,以便在所选时段内仅获得n个帐户?

1 个答案:

答案 0 :(得分:1)

你的查询有点混乱。第一个在语法上不正确。我认为你可以简化,意图是:

SELECT to_char(make_date(s.year, s.month, 1), 'YYYY-MM') AS period,
       a.id AS account_id, a.name AS account_name,
       COALESCE(SUM(s.net_sales), 0) AS amount,
       SUM(SUM(s.net_sales)) OVER (PARTITION BY a.id) as total
FROM sales s INNER JOIN
     account a
     ON a.id = s.account_id
WHERE make_date(s.year, s.month, 1) >= FROM_DATE AND
      make_date(s.year, s.month, 1) <= TO_DATE
GROUP BY s.year, s.month, a.id, a.name
ORDER BY s.year, s.month ASC;

如果您想按总销售额(或每月销售额)排名,那么您可以使用dense_rank()

SELECT ym.*
FROM (SELECT to_char(make_date(s.year, s.month, 1), 'YYYY-MM') AS period,
             a.id AS account_id, a.name AS account_name,
             COALESCE(SUM(s.net_sales), 0) AS amount,
             total,
             DENSE_RANK() OVER (ORDER BY total DESC) as seqnum
      FROM (SELECT s.*, SUM(s.net_sales) OVER (PARTITION BY client_id) as total
            FROM sales s
           ) s INNER JOIN
           account a
           ON a.id = s.account_id
      WHERE make_date(s.year, s.month, 1) >= FROM_DATE AND
            make_date(s.year, s.month, 1) <= TO_DATE
      GROUP BY s.year, s.month
     ) ym
WHERE seqnum <= 3
ORDER BY s.year, s.month ASC;