DISTINCT 和 ORDER BY 在同一个命令中,不使用 order by 变量

DISTINCT and ORDER BY in the same command without using the order by variable

我需要 select 用户最近玩过的 5 场比赛,但我不想重复。因此,我需要一条 SQL 行,将它们按从最近到最少的顺序排列,但还要确保没有明显区别。要订购它们,我有一个时间变量,但如果我使用:

select distinct name, image, time 
from history 
where userID = USERID 
order by time desc

这会删除除第一个之外的所有其他时间,这意味着我将按照首先玩游戏的顺序获得结果。

如果您仍然不明白这里是模式和我拥有的一些数据:

架构:

CREATE TABLE history (userID integer, name text not null, image text not null, time text not null);

数据:

6 | Arcade Mathematicians | arcadeMathematicians | 2021-04-17 07:59:00  
6 | Arcade Mathematicians | arcadeMathematicians | 2021-04-17 08:01:04  
6 | Infinite Spinner | infiniteSpinner | 2021-04-17 08:01:08  
6 | Arcade Mathematicians | arcadeMathematicians | 2021-04-17 08:01:12  
6 | Arcade Mathematicians | arcadeMathematicians | 2021-04-17 08:02:13  
6 | Infinite Spinner | infiniteSpinner | 2021-04-17 08:02:16  
6 | Arcade Mathematicians | arcadeMathematicians | 2021-04-17 08:03:16  
6 | Infinite Spinner | infiniteSpinner | 2021-04-17 08:03:18  
6 | Arcade Mathematicians | arcadeMathematicians | 2021-04-17 08:03:21 

所以如果你在这里看到如果我按时使用 distinct 它将不起作用,因为所有内容仍然会显示。

使用ROW_NUMBER() window函数根据用户和游戏对table的每一行进行排名,并按时间降序排列。
从这些结果中只保留等级 = 1 的行,这意味着每个用户和游戏组合的最新行。
然后再次使用 ROW_NUMBER() 根据用户对剩余行进行排名,并按时间降序排列,结果只保留排名 <= 5 的行:

WITH 
  cte1 AS (
    SELECT *, ROW_NUMBER() OVER (PARTITION BY userid, name ORDER BY time DESC) rn1
    FROM history
  ),
  cte2 AS (
    SELECT *, ROW_NUMBER() OVER (PARTITION BY userid ORDER BY time DESC) rn2
    FROM cte1
    WHERE rn1 = 1
  )
SELECT userid, name, image, time 
FROM cte2
WHERE rn2 <= 5 

如果您想要特定用户的结果更容易,只需使用 MAX() window 函数并对结果进行排序以获得前 5 行:

SELECT DISTINCT userid, name, image, 
       MAX(time) OVER (PARTITION BY name) time 
FROM history
WHERE userid = 6
ORDER BY time DESC LIMIT 5

或者,如果同一名称的图像行与行不同:

SELECT DISTINCT userid, name, 
       FIRST_VALUE(image) OVER (PARTITION BY name ORDER BY time DESC) image, 
       MAX(time) OVER (PARTITION BY name) time 
FROM history
WHERE userid = 6
ORDER BY time DESC LIMIT 5

参见demo
结果(对于您的示例数据):

userid name image time
6 Arcade Mathematicians arcadeMathematicians 2021-04-17 08:03:21
6 Infinite Spinner infiniteSpinner 2021-04-17 08:03:18

如果您有想要的特定用户,并且您想要该用户最近的五行,其中 name/image 是唯一的,您可以使用聚合:

select h.name, h.image, max(h.time)
from history h
where h.userID = ?    -- ? is the user you want 
group by h.name, h.image
order by max(h.time) desc
fetch first 1 row only;

并非所有数据库都支持标准 fetch first 子句。有些使用 limitselect top 或其他结构。