查找 SQL 中首次发生的事件
Find first occuring events in SQL
问题
在我们的应用程序中,我们存储房间清洁时间的重复事件。任务(事件)被分配给用户并被赋予一个类别。我们使用 SQL-视图 cleaning_tasks
来获取特定日期的所有计划任务。该视图将 return 类似于以下内容。
SELECT * FROM cleaning_tasks WHERE scheduled_at = current_date();
> room_id, user_id, category, scheduled_at
> 1, 1, 3, 2020-06-04
现在的问题是,我们想要获得按 room_id
、user_id
和 category
分组的第一个即将发生的事件。
例如,假设我们有三个必须每天清洁的 1 类房间和两个每周五清洁的 2 类房间。如果今天是星期三,那么我希望查询 return 类别 1 的三个事件和计划在周五发生的类别 2 的两个事件(标有 *
的行)如果它是星期五然后查询将 return 安排在星期五的所有五个事件。
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-05 # Friday
20, 2, 1, 2020-06-05
30, 3, 1, 2020-06-05
40, 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()
一个通常有效的选择是使用子查询进行过滤:
select ct.*
from cleaning_tasks ct
where ct.scheduled_at = (
select min(ct1.scheduled_at)
from cleaning_tasks ct1
where ct1.room_id = ct.room_id and ct1.scheduled_at >= current_date
)
为了性能,考虑在 (room_id, scheduled_at)
上建立索引。
如果我的理解正确的话,您希望今天或之后的第一个 "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
问题
在我们的应用程序中,我们存储房间清洁时间的重复事件。任务(事件)被分配给用户并被赋予一个类别。我们使用 SQL-视图 cleaning_tasks
来获取特定日期的所有计划任务。该视图将 return 类似于以下内容。
SELECT * FROM cleaning_tasks WHERE scheduled_at = current_date();
> room_id, user_id, category, scheduled_at
> 1, 1, 3, 2020-06-04
现在的问题是,我们想要获得按 room_id
、user_id
和 category
分组的第一个即将发生的事件。
例如,假设我们有三个必须每天清洁的 1 类房间和两个每周五清洁的 2 类房间。如果今天是星期三,那么我希望查询 return 类别 1 的三个事件和计划在周五发生的类别 2 的两个事件(标有 *
的行)如果它是星期五然后查询将 return 安排在星期五的所有五个事件。
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-05 # Friday
20, 2, 1, 2020-06-05
30, 3, 1, 2020-06-05
40, 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()
一个通常有效的选择是使用子查询进行过滤:
select ct.*
from cleaning_tasks ct
where ct.scheduled_at = (
select min(ct1.scheduled_at)
from cleaning_tasks ct1
where ct1.room_id = ct.room_id and ct1.scheduled_at >= current_date
)
为了性能,考虑在 (room_id, scheduled_at)
上建立索引。
如果我的理解正确的话,您希望今天或之后的第一个 "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