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
子句。有些使用 limit
、select top
或其他结构。
我需要 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
子句。有些使用 limit
、select top
或其他结构。