我有一个数据库表,其中包含一个人的ID,姓名和时间(以毫秒为单位,存储为int
)。例如:
| id | name | totalTime |
| --- | ------ | --------- |
| 1 | Bob | 16280 |
| 2 | Andy | 17210 |
| 3 | Bill | 15320 |
| 4 | Matt | 14440 |
| 5 | Steven | 17570 |
| 6 | Tom | NULL |
| 7 | Angus | 17210 |
| 8 | Will | NULL |
| 9 | Jack | 17410 |
| 10 | Alex | 16830 |
不一定所有人都有时间(因此为空)。
我想再加上两列-一列显示每个人的排名/位置,另一列显示最佳(即最小)时间与每一行时间之间的时间差(毫秒)。
我设法编写了一个MySQL 8.x查询,用于执行排名:
SELECT id, name, totalTime,
(CASE WHEN totalTime IS NOT NULL THEN RANK() OVER ( PARTITION BY (CASE WHEN totalTime IS NOT NULL THEN 1 ELSE 0 END) ORDER BY totalTime ) END) totalRank
FROM results
ORDER BY -totalRank DESC;
...并输出:
| id | name | totalTime | totalRank |
| --- | ------ | --------- | --------- |
| 4 | Matt | 14440 | 1 |
| 3 | Bill | 15320 | 2 |
| 1 | Bob | 16280 | 3 |
| 10 | Alex | 16830 | 4 |
| 2 | Andy | 17210 | 5 |
| 7 | Angus | 17210 | 5 |
| 9 | Jack | 17410 | 7 |
| 5 | Steven | 17570 | 8 |
| 6 | Tom | NULL | NULL |
| 8 | Will | NULL | NULL |
...但是无法找出SQL添加具有时差的另一列。
下面是我想要的示例,但不知道如何做:
| id | name | totalTime | totalRank | difference |
| --- | ------ | --------- | --------- | ---------- |
| 4 | Matt | 14440 | 1 | 0 |
| 3 | Bill | 15320 | 2 | 880 |
| 1 | Bob | 16280 | 3 | 1840 |
| 10 | Alex | 16830 | 4 | 2390 |
| 2 | Andy | 17210 | 5 | 2770 |
| 7 | Angus | 17210 | 5 | 2770 |
| 9 | Jack | 17410 | 7 | 2970 |
| 5 | Steven | 17570 | 8 | 3130 |
| 6 | Tom | NULL | NULL | NULL |
| 8 | Will | NULL | NULL | NULL |
我可以将其作为数据库提琴手使用:https://www.db-fiddle.com/f/gQvSeij2EKSufYp9VjbDav/0
在此先感谢您的帮助!
答案 0 :(得分:2)
您可以使用CTE
来获取最小值totalTime
并使用它来计算difference
:
WITH cte as (SELECT MIN(totalTime) minTotalTime FROM results)
SELECT id, name, totalTime,
CASE WHEN totalTime IS NOT NULL
THEN RANK() OVER (PARTITION BY (
CASE
WHEN totalTime IS NOT NULL THEN 1
ELSE 0
END
) ORDER BY totalTime)
END totalRank,
totalTime - (SELECT minTotalTime from cte) difference
FROM results
ORDER BY -totalRank DESC;
请参见demo。
结果:
| id | name | totalTime | totalRank | difference |
| --- | ------ | --------- | --------- | ---------- |
| 4 | Matt | 14440 | 1 | 0 |
| 3 | Bill | 15320 | 2 | 880 |
| 1 | Bob | 16280 | 3 | 1840 |
| 10 | Alex | 16830 | 4 | 2390 |
| 2 | Andy | 17210 | 5 | 2770 |
| 7 | Angus | 17210 | 5 | 2770 |
| 9 | Jack | 17410 | 7 | 2970 |
| 5 | Steven | 17570 | 8 | 3130 |
| 6 | Tom | | | |
| 8 | Will | | | |
答案 1 :(得分:1)
SELECT subtable.id,
subtable.NAME,
subtable.totalTime,
subtable.diff,
IIF(subtable.totalTime IS NULL,NULL,subtable.rowno) as bisi
FROM (
select *,
ROW_NUMBER() OVER (ORDER BY totalTime desc) as rowno,
totalTime -
(
select min(rst.totalTime)
from results rst) as diff
from results) subtable;
我会在MS-SQL或MYSQL中这样做
SELECT subtable.id,
subtable.NAME,
subtable.totalTime,
subtable.diff,
IF (subtable.totalTime IS NULL, NULL, subtable.rowno) as bisi
FROM (
select *,
ROW_NUMBER() OVER (ORDER BY totalTime desc) as rowno,
totalTime -
(
select min(rst.totalTime)
from results rst) as diff
from results) subtable;
答案 2 :(得分:1)
添加min()窗口函数
SELECT id, name, totalTime,
(CASE WHEN totalTime IS NOT NULL THEN RANK() OVER ( PARTITION BY (CASE WHEN totalTime IS NOT NULL THEN 1 ELSE 0 END) ORDER BY totalTime ) END) totalRank
,totaltime - min(totaltime) over() diff
FROM results
ORDER BY -totalRank DESC;
答案 3 :(得分:1)
塞尔格的答案是正确的。我将其写为:
SELECT id, name, totalTime,
(CASE WHEN totalTime IS NOT NULL
THEN RANK() OVER (PARTITION BY (totalTime IS NULL) ORDER BY totalTime)
END) as totalRank,
totaltime - MIN(totaltime) OVER() as diff
FROM results
ORDER BY (totalTime IS NOT NULL) DESC, totalRank;
区别是:
PARTITION BY
。您使用CASE
,但MySQL方便地将布尔值视为“真实”值。ORDER BY
。