计算最小值与每行值之间的差

时间:2019-06-30 08:27:22

标签: mysql sql

我有一个数据库表,其中包含一个人的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

在此先感谢您的帮助!

4 个答案:

答案 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;

区别是:

  1. 简化PARTITION BY。您使用CASE,但MySQL方便地将布尔值视为“真实”值。
  2. 以更直观的方式表达ORDER BY