我如何 select 此 table 中每个不同用户的最高分数?
How do I select the max score from each distinct user in this table?
我有以下 table (scores
):
id user date score
---|-----|------------|--------
1 | 10 | 11/01/2016 | 400
2 | 10 | 11/03/2016 | 450
5 | 17 | 10/03/2016 | 305
3 | 13 | 09/03/2016 | 120
4 | 17 | 11/03/2016 | 300
6 | 13 | 08/03/2016 | 120
7 | 13 | 11/12/2016 | 120
8 | 13 | 09/01/2016 | 110
我想 select max(score)
每个不同的用户,使用 date
作为决胜局(在平局的情况下,最近的记录应该是 returned) 使得结果如下所示(每个用户的最高分,按 score
降序排列):
id user date score
---|-----|------------|--------
2 | 10 | 11/03/2016 | 450
5 | 17 | 10/03/2016 | 305
7 | 13 | 11/12/2016 | 120
我正在使用 Postgres,无论如何我都不是 SQL 专家。我尝试了类似于以下的方法,但它不起作用,因为我没有 group by
:
中包含 id
列
select scores.user, max(scores.score) as score, scores.id
from scores
group by scores.user
order by score desc
我觉得我需要做一个子select,但我无法使连接正常工作。我找到了 How can I SELECT rows with MAX(Column value), DISTINCT by another column in SQL? 但我似乎无法使任何解决方案对我有用,因为我需要 return 该行的 id
并且我有可能在 date
列。
试试这个:
with
-- get maximum scores by user
maxscores as (
select "user", max(score) as maxscore
from test
group by "user"
),
-- find the maximum date as the tie-breaker along with the above information
maxdates as (
select t."user", mx.maxscore, max(t."date") as maxdate
from test t
inner join maxscores mx
on mx."user" = t."user"
and mx.maxscore = t.score
group by t."user", mx.maxscore
)
-- select all columns based on the results of maxdates
select t.*
from test t
inner join maxdates md
on md."user" = t."user"
and md.maxscore = t.score
and md.maxdate = t."date";
说明
- 使用 CTE maxdates,让我们找出每个用户的最高分数
- 回到table。获取匹配用户和最高分数的记录。获取该 user/score 组合的最大日期
- 回到table。获取与我们检索到的用户、最大分数和最大日期相匹配的行
示例:
http://sqlfiddle.com/#!15/0f756/8 - 没有 row_number
http://sqlfiddle.com/#!15/0f756/13 - row_number
您可以随意更改查询。
测试用例
create table test (
id int,
"user" int,
"date" date,
score int
);
insert into test values
(1 , 10 , '11/01/2016' , 400 )
,(2 , 10 , '11/03/2016' , 450 )
,(5 , 17 , '10/03/2016' , 305 )
,(3 , 13 , '09/03/2016' , 120 )
,(4 , 17 , '11/03/2016' , 300 )
,(6 , 13 , '08/03/2016' , 120 )
,(7 , 13 , '11/12/2016' , 120 )
,(8 , 13 , '09/01/2016' , 110);
结果
| id | user | date | score |
|----|------|----------------------------|-------|
| 2 | 10 | November, 03 2016 00:00:00 | 450 |
| 5 | 17 | October, 03 2016 00:00:00 | 305 |
| 7 | 13 | November, 12 2016 00:00:00 | 120 |
风险
如果用户 13 有两条相同分数和日期的记录(例如),您将获得 2 条记录用户 13。
风险示例:http://sqlfiddle.com/#!15/cb86e/1
为了降低风险,您可以像这样使用 row_number() over()
:
with
rankeddata as (
select row_number() over (
partition by
"user"
order by
"user",
score desc,
"date" desc) as sr,
t.*
from test t
)
select * from rankeddata where sr = 1;
降低风险的结果
| sr | id | user | date | score |
|----|----|------|----------------------------|-------|
| 1 | 2 | 10 | November, 03 2016 00:00:00 | 450 |
| 1 | 7 | 13 | November, 12 2016 00:00:00 | 120 |
| 1 | 5 | 17 | October, 03 2016 00:00:00 | 305 |
这样
create table test (
id int,
"user" int,
"date" date,
score int
);
insert into test values
(1 , 10 , '11/01/2016' , 400 )
,(2 , 10 , '11/03/2016' , 450 )
,(5 , 17 , '10/03/2016' , 305 )
,(3 , 13 , '09/03/2016' , 120 )
,(4 , 17 , '11/03/2016' , 300 )
,(6 , 13 , '08/03/2016' , 120 )
,(7 , 13 , '11/12/2016' , 120 )
,(8 , 13 , '09/01/2016' , 110);
select * from test where id in (
select distinct(first_value(id)
over(
partition by "user" order by score desc
))
from test
)
在 Postgres 中,通常最快的方法是使用 distinct on ()
select distinct on (user_id) *
from the_table
order by user_id, score desc;
这绝对比使用带有 max()
的子查询的任何解决方案快 lot,通常仍然比使用 [=27] 的等效解决方案快一点=] 函数(例如 row_number()
)
我使用 user_id
作为列名,因为 user
是一个保留字,我强烈建议不要使用它。
对于mysql查询
select sr, id, user, date, MAX(score) score
from the_table
group by user
order by score desc;
我有以下 table (scores
):
id user date score
---|-----|------------|--------
1 | 10 | 11/01/2016 | 400
2 | 10 | 11/03/2016 | 450
5 | 17 | 10/03/2016 | 305
3 | 13 | 09/03/2016 | 120
4 | 17 | 11/03/2016 | 300
6 | 13 | 08/03/2016 | 120
7 | 13 | 11/12/2016 | 120
8 | 13 | 09/01/2016 | 110
我想 select max(score)
每个不同的用户,使用 date
作为决胜局(在平局的情况下,最近的记录应该是 returned) 使得结果如下所示(每个用户的最高分,按 score
降序排列):
id user date score
---|-----|------------|--------
2 | 10 | 11/03/2016 | 450
5 | 17 | 10/03/2016 | 305
7 | 13 | 11/12/2016 | 120
我正在使用 Postgres,无论如何我都不是 SQL 专家。我尝试了类似于以下的方法,但它不起作用,因为我没有 group by
:
id
列
select scores.user, max(scores.score) as score, scores.id
from scores
group by scores.user
order by score desc
我觉得我需要做一个子select,但我无法使连接正常工作。我找到了 How can I SELECT rows with MAX(Column value), DISTINCT by another column in SQL? 但我似乎无法使任何解决方案对我有用,因为我需要 return 该行的 id
并且我有可能在 date
列。
试试这个:
with
-- get maximum scores by user
maxscores as (
select "user", max(score) as maxscore
from test
group by "user"
),
-- find the maximum date as the tie-breaker along with the above information
maxdates as (
select t."user", mx.maxscore, max(t."date") as maxdate
from test t
inner join maxscores mx
on mx."user" = t."user"
and mx.maxscore = t.score
group by t."user", mx.maxscore
)
-- select all columns based on the results of maxdates
select t.*
from test t
inner join maxdates md
on md."user" = t."user"
and md.maxscore = t.score
and md.maxdate = t."date";
说明
- 使用 CTE maxdates,让我们找出每个用户的最高分数
- 回到table。获取匹配用户和最高分数的记录。获取该 user/score 组合的最大日期
- 回到table。获取与我们检索到的用户、最大分数和最大日期相匹配的行
示例:
http://sqlfiddle.com/#!15/0f756/8 - 没有 row_number
http://sqlfiddle.com/#!15/0f756/13 - row_number
您可以随意更改查询。
测试用例
create table test (
id int,
"user" int,
"date" date,
score int
);
insert into test values
(1 , 10 , '11/01/2016' , 400 )
,(2 , 10 , '11/03/2016' , 450 )
,(5 , 17 , '10/03/2016' , 305 )
,(3 , 13 , '09/03/2016' , 120 )
,(4 , 17 , '11/03/2016' , 300 )
,(6 , 13 , '08/03/2016' , 120 )
,(7 , 13 , '11/12/2016' , 120 )
,(8 , 13 , '09/01/2016' , 110);
结果
| id | user | date | score |
|----|------|----------------------------|-------|
| 2 | 10 | November, 03 2016 00:00:00 | 450 |
| 5 | 17 | October, 03 2016 00:00:00 | 305 |
| 7 | 13 | November, 12 2016 00:00:00 | 120 |
风险
如果用户 13 有两条相同分数和日期的记录(例如),您将获得 2 条记录用户 13。
风险示例:http://sqlfiddle.com/#!15/cb86e/1
为了降低风险,您可以像这样使用 row_number() over()
:
with
rankeddata as (
select row_number() over (
partition by
"user"
order by
"user",
score desc,
"date" desc) as sr,
t.*
from test t
)
select * from rankeddata where sr = 1;
降低风险的结果
| sr | id | user | date | score |
|----|----|------|----------------------------|-------|
| 1 | 2 | 10 | November, 03 2016 00:00:00 | 450 |
| 1 | 7 | 13 | November, 12 2016 00:00:00 | 120 |
| 1 | 5 | 17 | October, 03 2016 00:00:00 | 305 |
这样
create table test (
id int,
"user" int,
"date" date,
score int
);
insert into test values
(1 , 10 , '11/01/2016' , 400 )
,(2 , 10 , '11/03/2016' , 450 )
,(5 , 17 , '10/03/2016' , 305 )
,(3 , 13 , '09/03/2016' , 120 )
,(4 , 17 , '11/03/2016' , 300 )
,(6 , 13 , '08/03/2016' , 120 )
,(7 , 13 , '11/12/2016' , 120 )
,(8 , 13 , '09/01/2016' , 110);
select * from test where id in (
select distinct(first_value(id)
over(
partition by "user" order by score desc
))
from test
)
在 Postgres 中,通常最快的方法是使用 distinct on ()
select distinct on (user_id) *
from the_table
order by user_id, score desc;
这绝对比使用带有 max()
的子查询的任何解决方案快 lot,通常仍然比使用 [=27] 的等效解决方案快一点=] 函数(例如 row_number()
)
我使用 user_id
作为列名,因为 user
是一个保留字,我强烈建议不要使用它。
对于mysql查询
select sr, id, user, date, MAX(score) score
from the_table
group by user
order by score desc;