SQLite 男女各比赛距离最佳 3 次

问题描述

我从这个简单的查询开始,该查询给出了在 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

假设以下数据:-

enter image description here

还假设您想要一个相对简单易懂的单个查询,那么以下可能适合:-

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 个单独的临时表。

使用结果上方的数据是(显然您可能希望对结果进行不同的排序):-

enter image description here

以下是用于测试上述并创建结果的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()