问题描述
我从这个简单的查询开始,该查询给出了在 125 公里比赛中取得最佳成绩(第一、第二和第三)的三个人。
SELECT *
FROM Coureurs
WHERE Genre=’M’ AND Epreuve='125km' AND TempsPassage IS NOT NULL
ORDER BY TempsPassage
LIMIT 3;
但是,我还需要在那个距离上时间最好的三个女人(流派= F)。 以及其他距离的最佳三男三女(TempsPassage=80km/65km/40km,..)。
这已经超出了我的水平……我真的想避免构建单独的“硬编码”查询。 提前致谢, 皮埃尔
解决方法
做出以下假设/更改
-
Epreuve 列是数字(存储 125,80 .... 而不是 125km,80km ....)
- 125 公里和 80 公里(如果排序)将看到 80 公里大于 125 公里
- 文本值会在额外的存储空间中花费一些
- 如果需要,可以很容易地提取附加 km 的值,例如
SELECT genre,Epreuve||'km',TempsPassage,Name FROM Coureurs
-
TempsPassage 列存储时间(示例使用秒,但请参阅 Time Values)
假设以下数据:-
还假设您想要一个相对简单易懂的单个查询,那么以下可能适合:-
WITH
m125 AS (SELECT * FROM Coureurs WHERE genre = 'M' AND Epreuve = 125 ORDER BY TempsPassage ASC LIMIT 3),f125 AS (SELECT * FROM Coureurs WHERE genre = 'F' AND Epreuve = 125 ORDER BY TempsPassage ASC LIMIT 3),m80 AS (SELECT * FROM Coureurs WHERE genre = 'M' AND Epreuve = 80 ORDER BY TempsPassage ASC LIMIT 3),f80 AS (SELECT * FROM Coureurs WHERE genre = 'F' AND Epreuve = 80 ORDER BY TempsPassage ASC LIMIT 3),m65 AS (SELECT * FROM Coureurs WHERE genre = 'M' AND Epreuve = 65 ORDER BY TempsPassage ASC LIMIT 3),f65 AS (SELECT * FROM Coureurs WHERE genre = 'F' AND Epreuve = 65 ORDER BY TempsPassage ASC LIMIT 3),m40 AS (SELECT * FROM Coureurs WHERE genre = 'M' AND Epreuve = 40 ORDER BY TempsPassage ASC LIMIT 3),f40 AS (SELECT * FROM Coureurs WHERE genre = 'F' AND Epreuve = 40 ORDER BY TempsPassage ASC LIMIT 3)
SELECT * FROM m125
UNION SELECT * FROM f125
UNION SELECT * FROM m80
UNION SELECT * FROM f80
UNION SELECT * FROM m65
UNION SELECT * FROM f65
UNION SELECT * FROM m40
UNION SELECT * FROM f40
ORDER BY Epreuve DESC,Genre DESC,TempsPassage ASC
;
这利用了所谓的 CTE(通用表表达式),它们基本上是临时表。
每个流派和 Epreuve (2 * 4 = 8) 的排列使用一个 CTE,它是用类似的查询构建的。
创建所有 CTE 后,将使用 UNION 组合 8 个单独的临时表。
使用结果上方的数据是(显然您可能希望对结果进行不同的排序):-
以下是用于测试上述并创建结果的SQL:-
DROP TABLE IF EXISTS Coureurs;
CREATE TABLE IF NOT EXISTS Coureurs (Genre TEXT,Epreuve int,TempsPassage int,name TEXT);
INSERT INTO Coureurs VALUES
('M',125,600,'Fred'),('M',610,'Bert'),630,'Harry'),620,'Albert'),575,'David'),('F',615,'Mary'),625,'Anne'),601,'Betty'),'Sue'),670,'Shelia'),80,450,'Louise'),460,'Celia'),425,'Debra'),475,'Diana'),65,350,'Zara'),360,'Yvonne'),325,'Wilma'),375,'Ursurla'),40,250,'Tracy'),260,'Rhona'),225,'Samantha'),275,'Karen'),'Lou'),'Colin'),'Danny'),'Eddy'),'Zed'),'Mark'),'William'),'Tom'),'Jim'),'Larry'),'Peter'),'Ronald')
;
SELECT * FROM Coureurs ORDER BY Random();
/* Easiest to understand - combining individual queries as CTE
CTE = Common Table Expression (equates to temporary table)
*/
WITH
m125 AS (SELECT * FROM Coureurs WHERE genre = 'M' AND Epreuve = 125 ORDER BY TempsPassage ASC LIMIT 3),TempsPassage ASC
;
DROP TABLE IF EXISTS Coureurs;
,
您可以使用窗口函数 ROW_NUMBER()
对每个种族/流派的结果进行排名,然后过滤以仅返回排名 1-3:
SELECT *
FROM (
SELECT *,ROW_NUMBER() OVER (PARTITION BY Epreuve,Genre ORDER BY TempsPassage) rn
FROM Coureurs
WHERE TempsPassage IS NOT NULL
)
WHERE rn <= 3
ORDER BY (Epreuve + 0),Genre,rn
如果有平局,那么可以尝试RANK()
窗口函数而不是ROW_NUMBER()
。