选择“每组最大n”所需的子查询深度

时间:2014-07-11 07:04:22

标签: sql postgresql greatest-n-per-group window-functions

我有一张包含idnameteam和&另一个人score为一群人。

Scores                    People       
--------------------      --------------
id  people_id  score      id  name  team                    
1   1          10         1   Sam   A                 
2   1          20         2   Jon   B                 
3   2          5          3   Mat   C                
4   3          15         4   Ted   A                 
5   4          2          5   Tim   A            
6   3          5          ...                               
7   4          7    
...                                     

我想总结每支球队的得分,然后对得分进行排名&获得每个团队的前2名,如下所示。

我的查询有3个级别的选择。 我可以通过在第二个选择中使用条款WHERE rank_score < 3来将其简化为2级

SELECT "id", "name", "team", "rank_score"
FROM
  ( SELECT "id", "name", "team"
    ROW_NUMBER() OVER (PARTITION BY "team" ORDER BY "count_score" DESC) AS "rank_score"
    FROM 
      (SELECT "id", "name", "team"
       COUNT("score") AS  "count_score"
       FROM "people"
       INNER JOIN "scores" on ("scores"."people_id" = "people"."id")
       GROUP BY "id", "name", "team"
      ) AS "count_table"
  ) AS "rank_table"
WHERE rank_score < 3

输出所需:

1st SELECT output
-----------------
id  name  team count_score
1   Sam   A    30 
2   Jon   B    5
3   Mat   C    20
4   Ted   A    9
5   Tim   A    0
....

2nd SELECT output
-----------------
id  name  team rank_score
1   Sam   A    1 
2   Jon   B    4
3   Mat   C    2
4   Ted   A    3
5   Tim   A    5
....

3rd SELECT output
-----------------
id  name  team rank_score
1   Sam   A    1 
2   Jon   B    4
3   Mat   C    2
4   Ted   A    3
....

2 个答案:

答案 0 :(得分:1)

您可以避免一个级别(按分数(分数)的顺序可以在PARTITION子句中完成。)

SELECT id, name, team, rank_score
FROM
  ( SELECT p.id, p.name, p.team,
    ROW_NUMBER() OVER (PARTITION BY team ORDER BY count(score) DESC) AS rank_score
    FROM  people p
    JOIN scores s on s.people_id = p.id
    GROUP BY p.id, p.name, p.team
  )  rank_table
WHERE rank_score < 3;

查看SqlFiddle查询(已更正)和此查询

使用cte(不会改变问题的根源,但可能更具可读性)

with rank_cte as (SELECT p.id, p.name, p.team,
    ROW_NUMBER() OVER (PARTITION BY team ORDER BY count(score) DESC) AS rank_score
    FROM people p
    join scores s on s.people_id = p.id
   group by p.id, p.name, p.team)

select * from rank_cte
where rank_score <3;

答案 1 :(得分:-1)

您可以使用CTE。这是一个例子

WITH Sales_CTE (SalesPersonID, SalesOrderID, SalesYear)
AS
-- Define the CTE query.
(
    SELECT SalesPersonID, SalesOrderID, YEAR(OrderDate) AS SalesYear
    FROM Sales.SalesOrderHeader
    WHERE SalesPersonID IS NOT NULL
)
-- Define the outer query referencing the CTE name.
SELECT SalesPersonID, COUNT(SalesOrderID) AS TotalSales, SalesYear
FROM Sales_CTE
GROUP BY SalesYear, SalesPersonID
ORDER BY SalesPersonID, SalesYear;

我确定你会将它应用于你的代码:)

编辑 - 另外,你知道你只使用count()来计算行数,而不是得分。您需要使用SUM()