在SQL中查找首次发生的事件

问题描述 投票:1回答:2

问题

在我们的应用程序中,我们存储应定期清理房间的重复事件。任务(事件)被分配给用户并被赋予类别。我们使用SQL视图cleaning_tasks来获取特定日期的所有计划任务。该视图将返回类似以下内容的内容。

SELECT * FROM cleaning_tasks WHERE scheduled_at = current_date();

> room_id, user_id, category, scheduled_at
>       1,       1,        3,   2020-06-04

现在的问题是,我们希望获得按room_iduser_idcategory分组的第一个即将发生的事件。

例如,假设我们有三个类别为1的房间,必须每天清洁,两个类别为2的房间,每个星期五都要清洁。如果今天是星期三,那么我希望查询返回计划在星期五(类别为*的行)发生的类别1的三个事件和类别2的两个事件。如果是星期五,则查询将返回所有五个活动都安排在星期五。

room_id, user_id, category, scheduled_at
----------------------------------------
     10,       1,        1,   2020-06-03 * # Wednesday 
     20,       2,        1,   2020-06-03 *
     30,       3,        1,   2020-06-03 *
     10,       1,        1,   2020-06-04   # Thursday
     20,       2,        1,   2020-06-04
     30,       3,        1,   2020-06-04
     10,       1,        1,   2020-06-04   # Friday
     20,       2,        1,   2020-06-04
     30,       3,        1,   2020-06-04
     30,       4,        2,   2020-06-05 *         
     50,       5,        2,   2020-06-05 *

我的尝试

我尝试了以下查询,但得到的结果正确,但是由于GROUP BY,我不确定结果是否总是正确的。 SQL视图正在检索的事件是按顺序创建的。

SELECT room_id, user_id, category, scheduled_at
FROM room_cleaning_tasks
WHERE scheduled_at >= current_date()
GROUP BY room_id, user_id, category

我首先尝试使用MIN,但注意到我得到了错误的结果。可能是由于GROUP BY

SELECT room_id, user_id, category, scheduled_at, MIN(scheduled_at)
FROM cleaning_tasks
WHERE scheduled_at >= current_date()
GROUP_BY room_id, user_id, category

我也尝试在子查询中使用MIN,但这没有用。我很确定内部连接由于子查询中的MIN而失败。

SELECT t.room_id, t.user_id, t.category, t.scheduled_at
FROM (
  SELECT room_id, user_id, category, MIN(scheduled_at) scheduled_at
  FROM cleaning_tasks
  GROUP BY room_id, user_id, category
) upcoming
INNER JOIN cleaning_tasks
  ON t.room_id = upcoming.room_id
  AND t.user_id = upcoming.user_id
  AND t.category = upcoming.category
  AND t.category >= current_date()
sql date select mariadb greatest-n-per-group
2个回答
0
投票

一个选项是使用子查询进行过滤:

select ct.* 
from cleaning_tasks ct
where 
    ct.scheduled_at = current_date
    or ct.scheduled_at = (
        select min(ct1.scheduled_at)
        from cleaning_tasks ct1
        where ct1.scheduled_at > current_date and ct1.room_id = ct.room_id
    )

0
投票

如果我对您的理解正确,那么您希望今天或之后的第一个“ scheduled_at”日期按房间,用户和类别进行分组。

我将使用ROWNUMBER()OVER(PARTITION BY),并将其放在子查询中,以便进行过滤。

例如:

SELECT SUB.*
FROM (
      SELECT ROOM_ID
      , USER_ID
      , CATEGORY
      , SCHEDULED_AT
      , ROW_NUMBER() OVER (PARTITION BY ROOM_ID, USER_ID, CATEGORY 
                           ORDER BY SCHEDULED_AT ASC) AS ITEM_NUMBER
      FROM CLEANING_TASKS
      WHERE SCHEDULED_AT >= CURRENT_DATE
      ) SUB
WHERE ITEM_NUMBER = 1
© www.soinside.com 2019 - 2024. All rights reserved.