Select SQLite 中按连续日期排列的行
Select Rows by Consecutive Dates in SQLite
我有一个 table 数据如下:
日志Table:
User Id
Login Date
1
2022-01-03
1
2022-01-04
1
2022-01-10
1
2022-01-11
1
2022-01-12
1
2022-01-23
1
2022-01-25
1
2022-01-26
1
2022-01-27
1
2022-01-28
我想要做的是创建一个查询,其中 return 连续日期的最新登录行,使用 var_date 作为参数。
如果var_date是2022-01-29,那么结果是:
User Id
Login Date
1
2022-01-25
1
2022-01-26
1
2022-01-27
1
2022-01-28
如果 var_date 是 2022-01-30,则不会 returned,因为 2022-01-29 不在 table.
中
如果 var_date 是 2022-01-24,则查询将 return 以 2022-01-23 作为登录日期的行。
我如何在 SQLite 中执行此操作?
谢谢。
这个问题是间隙和孤岛的变体,孤岛是每个用户的记录集群,具有连续的日期。这是一种使用解析函数的方法:
WITH cte AS (
SELECT *, CASE WHEN julianday(LoginDate) -
julianday(LAG(LoginDate) OVER (PARTITION BY UserID
ORDER BY LoginDate))
> 1 THEN 1 ELSE 0 END AS counter
FROM yourTable
),
cte2 AS (
SELECT *, SUM(counter) OVER (PARTITION BY UserID ORDER BY LoginDate) AS grp
FROM cte
)
SELECT UserID, LoginDate
FROM cte2 t1
WHERE LoginDate < '2022-01-29' AND
grp = (SELECT t2.grp FROM cte2 t2
WHERE t2.UserID = t1.UserID AND t2.LoginDate = '2022-01-28');
这两个 CTE 为每个用户的每个集群生成一个伪数据组。最终查询 returns 所有小于目标日期的记录,其组值与前一个日期相同。因此,对于给定用户没有即时记录的日期,查询将为 return 空集。
使用递归 CTE:
WITH cte(UserId, LoginDate) AS (
SELECT :var_user_id, :var_date
UNION ALL
SELECT UserId, date(c.LoginDate, '-1 day')
FROM cte c
WHERE EXISTS (SELECT 1 FROM tablename t WHERE t.UserId = c.UserId AND t.LoginDate = date(c.LoginDate, '-1 day'))
)
SELECT *
FROM cte
WHERE LoginDate < (SELECT MAX(LoginDate) FROM cte);
将 :var_user_id
和 :var_date
更改为您想要的用户 ID 和日期值。
参见demo。
我有一个 table 数据如下:
日志Table:
User Id | Login Date |
---|---|
1 | 2022-01-03 |
1 | 2022-01-04 |
1 | 2022-01-10 |
1 | 2022-01-11 |
1 | 2022-01-12 |
1 | 2022-01-23 |
1 | 2022-01-25 |
1 | 2022-01-26 |
1 | 2022-01-27 |
1 | 2022-01-28 |
我想要做的是创建一个查询,其中 return 连续日期的最新登录行,使用 var_date 作为参数。
如果var_date是2022-01-29,那么结果是:
User Id | Login Date |
---|---|
1 | 2022-01-25 |
1 | 2022-01-26 |
1 | 2022-01-27 |
1 | 2022-01-28 |
如果 var_date 是 2022-01-30,则不会 returned,因为 2022-01-29 不在 table.
中如果 var_date 是 2022-01-24,则查询将 return 以 2022-01-23 作为登录日期的行。
我如何在 SQLite 中执行此操作?
谢谢。
这个问题是间隙和孤岛的变体,孤岛是每个用户的记录集群,具有连续的日期。这是一种使用解析函数的方法:
WITH cte AS (
SELECT *, CASE WHEN julianday(LoginDate) -
julianday(LAG(LoginDate) OVER (PARTITION BY UserID
ORDER BY LoginDate))
> 1 THEN 1 ELSE 0 END AS counter
FROM yourTable
),
cte2 AS (
SELECT *, SUM(counter) OVER (PARTITION BY UserID ORDER BY LoginDate) AS grp
FROM cte
)
SELECT UserID, LoginDate
FROM cte2 t1
WHERE LoginDate < '2022-01-29' AND
grp = (SELECT t2.grp FROM cte2 t2
WHERE t2.UserID = t1.UserID AND t2.LoginDate = '2022-01-28');
这两个 CTE 为每个用户的每个集群生成一个伪数据组。最终查询 returns 所有小于目标日期的记录,其组值与前一个日期相同。因此,对于给定用户没有即时记录的日期,查询将为 return 空集。
使用递归 CTE:
WITH cte(UserId, LoginDate) AS (
SELECT :var_user_id, :var_date
UNION ALL
SELECT UserId, date(c.LoginDate, '-1 day')
FROM cte c
WHERE EXISTS (SELECT 1 FROM tablename t WHERE t.UserId = c.UserId AND t.LoginDate = date(c.LoginDate, '-1 day'))
)
SELECT *
FROM cte
WHERE LoginDate < (SELECT MAX(LoginDate) FROM cte);
将 :var_user_id
和 :var_date
更改为您想要的用户 ID 和日期值。
参见demo。