MySQL 按 ID 和最新日期时间分组

Posted

技术标签:

【中文标题】MySQL 按 ID 和最新日期时间分组【英文标题】:MySQL Group by ID and Latest Datetime 【发布时间】:2012-09-26 23:18:40 【问题描述】:

我在这里看到了类似类型的问题,但没有一个对我的情况有所帮助。

我有一张表,可以说测试(使用 mysql MyISAM)

测试具有以下架构:

    TID INT PRIMARY KEY AUTO_INCREMENT
    TData varchar (data that i want to select)
    TUserID INT (this will be joined with users table, same users can have many records here)
    TViewedAt DATETIME (records each time user visits page, datetime format)

现在,每次当前登录的用户访问测试页面时,它都会将记录添加到此表中,记录访问者的用户 ID,用户访问的一些数据和日期和时间,每次都会自动递增 TID。

然后我有一个后端管理页面,我可以在其中查看哪个用户访问了测试页面、访问了多少次、数据和时间。基本上它是一个包含 20-25 个最新行列表的表格。我的查询应该只为每个数据选择一条记录。用户的数据可以相同,但时间不同,但我只想为每个用户选择一个最新的数据。因此,如果用户访问测试页面 10 次,则有 10 条记录进入数据库,但表中仅显示 1 条最新记录。如果另一个用户访问页面 15 次,它会显示第二个用户的 1 条记录,这又是最新的,所以现在我们总共有 2 行显示在表格上。我得到了一切工作,但出于某种原因 GROUP BY 并且 MAX(date) 没有给我每个日期的最新日期时间。

这是我的查询:

   SELECT *
   FROM Test
   WHERE TUserID = 123
   GROUP BY TData
   ORDER BY TViewedAt

返回 2 行,其中所有行都不是最新的。

非常感谢

【问题讨论】:

【参考方案1】:

我认为通过以下您可以实现您所需要的,这些操作就是所谓的“Group-wise Maximum”。

选项 1

这是最容易理解的,因为maxGroup By 一起使用,所以子查询将为所有用户返回最大的TID,然后我们执行其他查询来获取这些ID 的所有数据。

 Select TID, TData, TUserID, TViewedAt
 From Test 
 Where TID In(
    Select Max(TID)
    From Test
    Group By TUserID
)

选项 2

理解起来稍微复杂一些,但很可能更有效,这是基于当t1.TViewedAt 处于最大值时,没有更大值的t2.TViewedAt 并且t2 行值将是@987654328 @。

SELECT t1.TID, t1.TData, t1.TUserID, t1.TViewedAt
FROM Test t1
LEFT JOIN Test t2 ON t1.TUserID = t2.TUserID AND t1.TViewedAt < t2.TViewedAt
WHERE t2.TUserID IS NULL;

结果

TID TData   TUserID   TViewedAt
4   test3   123       2012-10-05 00:00:00.000
5   test2   213       2012-10-03 00:00:00.000

【讨论】:

有没有什么更高效的方法,即不需要子查询?我发现它正在杀死我的服务器 它也对我有用。但我还是不明白。有人可以为我分享更多资源吗?谷歌对我来说很难,不知道要问的条件。 @ApitJohnIsmail,我现在在转换技术时对 SQL 有点生疏了,但我相信这种分组称为 Group-wise Maximum 可能在 google 中寻找这个术语可能会帮助你。这是一个有用的链接:dev.mysql.com/doc/refman/5.7/en/…【参考方案2】:

以下查询,可能对您有所帮助-

select * from pages where date(create_date)=(select date(create_date) from pages order by create_date limit 1)

【讨论】:

你能解释一下这是如何回答这个问题的吗?【参考方案3】:
SELECT t1.TData, t1.TUserID, t1.TViewedAt 
FROM Test t1
JOIN
(SELECT TUserID, MAX(TViewedAt)
FROM Test
GROUP BY TUserID) t2
ON t1.TUserID = t2.TUserID AND t1.TViewedAt=t2.TViewedAt

【讨论】:

【参考方案4】:

您需要GROUP BY TUserID 以获得最大聚合。

SELECT
  TID,
  TData,
  main.TUserID
  main.TViewedAt
FROM
  yourTable main
  JOIN ( 
    SELECT TUserID, MAX(TViewedAt) AS TViewedAT FROM yourTable GROUP BY TUserID
  ) tmax ON main.TUserID = tmax.TUserID AND main.TViewedAt = tmax.TViewedAt

这是一种结合子查询的可移植方法。子查询为每个用户提取最新的TUserID,TViewedAt,并将其与主表结合起来以提取匹配的TData

如果您一次只需要一个用户,您可以这样做:

SELECT 
  TData,
  TViewedAt
FROM yourTable
WHERE TUserID = 'someid'
GROUP BY TUserId
HAVING TViewedAt = MAX(TViewedAt)

以上内容只能在 MySQL 中以我编写的方式工作。其他 RDBMS 会抱怨 TData 出现在 SELECT 列表中但不在 GROUP BY 中。

【讨论】:

我尝试的第二个并返回 0 行。 TViewedAt 是 DATETIME 格式 MAX 明白吗? @Giorgi MAX() 理解日期时间列。使用第一个,但添加一个 WHERE 子句来限制您想要的用户。第一个是两者中更好、更便携的。

以上是关于MySQL 按 ID 和最新日期时间分组的主要内容,如果未能解决你的问题,请参考以下文章

MySQL查询根据按月分组的激活日期计算累积用户数

按日期分组的 MySQL 累积总和

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

按最新日期获取分组后的列

Mysql按日期时间的日期部分分组,并为每个日期选择具有最大日期时间的行

在mysql和php中按日期范围分组