从每组中的 3 个表中选择 sql 中具有最新日期的行

Posted

技术标签:

【中文标题】从每组中的 3 个表中选择 sql 中具有最新日期的行【英文标题】:select rows in sql with latest date from 3 tables in each group 【发布时间】:2020-06-29 04:35:34 【问题描述】:

我正在为我的应用程序创建 PREDICATE 系统。

请看我已经看过的图片

我有一个问题,如何在 SQL 中为每个“QuizESId”列选择具有最新日期“Taken On”列表的行,在此之前我了解如何选择它,但它只使用一个表,我从中学习 select rows in sql with latest date for each ID repeated multiple times

这是我已经尝试过的

SELECT tt.*
FROM myTable tt
INNER JOIN 
    (SELECT ID, MAX(Date) AS MaxDateTime
     FROM myTable
     GROUP BY ID) groupedtt ON tt.ID = groupedtt.ID 
                            AND tt.Date = groupedtt.MaxDateTime

我这里比较困惑的是如何从3个表中进行选择,希望您能指导我,当然我需要一个查询良好且性能高效的解决方案。

谢谢

【问题讨论】:

您可以在“Taken On”列中使用order by。 Bad habits to kick : using old-style JOINs - 旧式 逗号分隔的表格列表 样式已替换为 ANSI 中的 proper ANSI JOIN 语法-92 SQL 标准(25 多年前),不鼓励使用它 @marc_s 谢谢你的建议,我知道使用旧样式是不可读的,但是性能如何,和加入一样吗? 感谢@marc_s,它真的是很好的指导,我从中得到了很多。回到我的问题,你能回答我的问题吗 您使用的是哪种 DBMS 产品? “SQL”只是一种查询语言,而不是特定数据库产品的名称。 Why should I tag my DBMS 【参考方案1】:

这适用于 SQL Server(您没有具体说明您使用的是什么 RDBMS):

如果您想获得“每个 QuizId 的最新行” - 这听起来像您需要具有 ROW_NUMBER() 值的 CTE(公用表表达式) - 类似这样(更新: 你显然想“分区”不只是QuizId,还需要UserName):

WITH BaseData AS
(
    SELECT 
        mAttempt.Id AS Id,
        mAttempt.QuizModelId AS QuizId,
        mAttempt.StartedAt AS StartsOn,
        mUser.UserName,
        mDetail.Score AS Score,
        RowNum = ROW_NUMBER() OVER (PARTITION BY mAttempt.QuizModelId, mUser.UserName
                                    ORDER BY mAttempt.TakenOn DESC)
    FROM 
        UserQuizAttemptModels mAttempt
    INNER JOIN 
        AspNetUsers mUser ON mAttempt.UserId = muser.Id
    INNER JOIN
        QuizAttemptDetailModels mDetail ON mDetail.UserQuizAttemptModelId = mAttempt.Id
)
SELECT *
FROM BaseData
WHERE QuizId = 10053  
  AND RowNum = 1

BaseData CTE 基本上选择数据(就像您所做的那样) - 但它也添加了一个 ROW_NUMBER() 列。这会将您的数据“分区”为数据组 - 基于 QuizModelId - 并且它将对每个数据组内的所有行进行编号,从 1 开始,并按第二个条件 - ORDER BY 子句排序。您说您想按“开始”日期订购 - 但在您的查询中没有显示这样的日期 - 所以我只是猜测它可能在 UserQuizAttemptModels 表上 - 根据需要进行更改和调整。

现在,您可以使用原始 WHERE 条件从该 CTE 中进行选择 - 并且您指定,您只需要每个数据组(对于每个“QuizId”)的第一行 - 具有最新“开始”的那一行" 日期值。

【讨论】:

我从 Mike Hernandez 的 Database Design fo Mere Mortals 那里学到了 DB 设计的基础知识。对于性能调优,我强烈推荐 Grant Fritchey 的 SQL Server 2017 Query Performance Tuning: Troubleshoot and Optimize Query Performance。 此查询将执行良好如果您有适当的索引 - 任何外键列都应该被索引,如果您有 WHERE 子句,该列 (或那些列)如果可能的话也应该被索引。但它也将在很大程度上取决于您的数据 - 数据的多少,数据的“形状”是什么。性能是一个非常复杂的主题 - 除非您可以实际处理具体数据,否则不容易处理...... 不太确定我是否理解您的问题。也许您对构成“数据组/分区”的定义不完整?也许您需要改用PARTITION BY QuizModelId, mUser.UserName? (如果我正确理解了你想要做什么......) 哦,是的,感谢您的书籍​​建议,我会购买并学习,希望能像您一样成为专家 正如我所说 - 您需要分区不仅是 QuizId,还需要“姓名” - 试试这个:ROW_NUMBER() OVER (PARTITION BY mAttempt.QuizModelId, mUser.UserName - 会返回正确的结果吗?

以上是关于从每组中的 3 个表中选择 sql 中具有最新日期的行的主要内容,如果未能解决你的问题,请参考以下文章

SQL - 按电子邮件和最新日期分组

Oracle:将两个表与一个公共列加上第二个表中的一个附加列(最新生效日期)连接以选择其他列

SQL Server 仅更新组中的最新记录

Laravel Eloquent/DB 选择每组前 1 行

如何从 2 个表中选择最近的日期时间

如何连接表以选择连接表中的最大行? [复制]