【问题标题】:DISTINCT and ORDER BY in the same command without using the order by variable同一命令中的 DISTINCT 和 ORDER BY 不使用 order by 变量
【发布时间】:2021-07-12 02:56:45
【问题描述】:

我需要选择用户最近参加的 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,它将无法正常工作,因为仍然会显示所有内容。

【问题讨论】:

  • (1) 用您正在使用的数据库标记您的问题。 (2) 您的描述涉及一种叫做“游戏”的东西,但您的数据库中没有这样的实体或列。

标签: sql sql-order-by distinct


【解决方案1】:

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

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() 窗口函数并对结果进行排序以获得前 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

【讨论】:

  • 嗯,好的,我会尽快尝试,谢谢!
  • 我真的不明白 ROW_NUMBER() 你能解释一下吗@forpas?
  • @infinity_ninja1239 你可以读到她:mysqltutorial.org/mysql-window-functions/…
  • 嗨@forpas,你的建议很棒而且很有效,但唯一的问题,部分是我的错,是它只给了我最近的游戏,因为我给你的数据是第 6 个用户历史,但这是一个简单的修复,所以谢谢!
  • @infinity_ninja1239 如果您想要 1 个用户的结果,请查看我编辑的答案以获得更简单的解决方案。
【解决方案2】:

如果您有想要的特定用户,并且希望该用户的最近五行名称/图像是唯一的,则可以使用聚合:

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 或其他构造。

【讨论】:

  • 是的,我确实希望来自特定用户,但我希望它们都是不同的,并且在回答您的第二个问题时,这是一个历史表,其中记录了用户的游戏历史,以便显示在 HTML 页面上给他们。图片栏是为了显示图片,名字栏是显示名字,时间是这样,我们可以按时间排序,得到他们最近玩过的游戏。 @戈登林诺夫
  • @infinity_ninja1239 。 . .那么我认为这回答了你的问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-01-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多