将 SQL 组更改行转换为日期
Turn set of SQL change rows into dates
我有一个 table (visibility_history
) 可以跟踪用户更改个人资料可见性的日期。我们在首次创建用户个人资料时创建 1 visibility_history
行,并在用户更改其个人资料可见性时创建其他行。
看起来差不多
user_id
visible_before
visible_after
日期
1
无
正确
2021 年 1 月 1 日
1
正确
错误
2021 年 1 月 4 日
1
错误
正确
2021 年 1 月 5 日
2
无
错误
2021 年 1 月 4 日
3
无
正确
2021 年 1 月 4 日
在上面的示例中,用户 1 是在 1 月 1 日创建的,用户 2 和 3 是在 1 月 4 日创建的。对于表示用户可见度变化的每一行,我们在变化与变化后
我想要查询 return 每个用户的个人资料可见的日期集。例如,我将查询 return 用户个人资料在 1 月 2 日至 1 月 6 日之间可见的日期。结果将是
user_id
日期
1
2021 年 1 月 2 日
1
2021 年 1 月 3 日
1
2021 年 1 月 5 日
1
2021 年 1 月 6 日
3
2021 年 1 月 4 日
3
2021 年 1 月 5 日
3
2021 年 1 月 6 日
我认为我需要使用计数 table 但我不知道在这种情况下如何使用。
您需要定义您感兴趣的界限,因为它无法从您想要的 1 月 6 日而不是 1 月 7 日的样本数据中确定。我在我的解决方案中使用了 calendar
CTE,无论如何您可以硬编码日期常量,如果你要。
然后您预先计算每个可见性间隔的上限(含)(我假设没有行带有 visible_before = visible_after
),并根据匹配的适当日期范围为每个用户加入具有有效间隔的预生成日期。
with visibility_history (user_id,visible_before,visible_after,date) as (values
(1,null ,true , date '2021-01-01'),
(1,true ,false, date '2021-01-04'),
(1,false,true , date '2021-01-05'),
(2,null ,false, date '2021-01-04'),
(3,null ,true , date '2021-01-04')
), calendar (min_date, max_date) as (values
(date '2021-01-02', date '2021-01-06')
), precomputed_interval (user_id, visible_after, since, till) as (
select h.user_id, h.visible_after, h.date
, coalesce(lead(h.date) over (partition by h.user_id order by h.date) - interval '1 day', calendar.max_date)
from visibility_history h
cross join calendar
)
select i.user_id, s.d
from generate_series((select min_date from calendar), (select max_date from calendar), '1 day'::interval) as s(d)
join precomputed_interval i on s.d between i.since and i.till
where i.visible_after
order by i.user_id, s.d
我有一个 table (visibility_history
) 可以跟踪用户更改个人资料可见性的日期。我们在首次创建用户个人资料时创建 1 visibility_history
行,并在用户更改其个人资料可见性时创建其他行。
看起来差不多
user_id | visible_before | visible_after | 日期 |
---|---|---|---|
1 | 无 | 正确 | 2021 年 1 月 1 日 |
1 | 正确 | 错误 | 2021 年 1 月 4 日 |
1 | 错误 | 正确 | 2021 年 1 月 5 日 |
2 | 无 | 错误 | 2021 年 1 月 4 日 |
3 | 无 | 正确 | 2021 年 1 月 4 日 |
在上面的示例中,用户 1 是在 1 月 1 日创建的,用户 2 和 3 是在 1 月 4 日创建的。对于表示用户可见度变化的每一行,我们在变化与变化后
我想要查询 return 每个用户的个人资料可见的日期集。例如,我将查询 return 用户个人资料在 1 月 2 日至 1 月 6 日之间可见的日期。结果将是
user_id | 日期 |
---|---|
1 | 2021 年 1 月 2 日 |
1 | 2021 年 1 月 3 日 |
1 | 2021 年 1 月 5 日 |
1 | 2021 年 1 月 6 日 |
3 | 2021 年 1 月 4 日 |
3 | 2021 年 1 月 5 日 |
3 | 2021 年 1 月 6 日 |
我认为我需要使用计数 table 但我不知道在这种情况下如何使用。
您需要定义您感兴趣的界限,因为它无法从您想要的 1 月 6 日而不是 1 月 7 日的样本数据中确定。我在我的解决方案中使用了 calendar
CTE,无论如何您可以硬编码日期常量,如果你要。
然后您预先计算每个可见性间隔的上限(含)(我假设没有行带有 visible_before = visible_after
),并根据匹配的适当日期范围为每个用户加入具有有效间隔的预生成日期。
with visibility_history (user_id,visible_before,visible_after,date) as (values
(1,null ,true , date '2021-01-01'),
(1,true ,false, date '2021-01-04'),
(1,false,true , date '2021-01-05'),
(2,null ,false, date '2021-01-04'),
(3,null ,true , date '2021-01-04')
), calendar (min_date, max_date) as (values
(date '2021-01-02', date '2021-01-06')
), precomputed_interval (user_id, visible_after, since, till) as (
select h.user_id, h.visible_after, h.date
, coalesce(lead(h.date) over (partition by h.user_id order by h.date) - interval '1 day', calendar.max_date)
from visibility_history h
cross join calendar
)
select i.user_id, s.d
from generate_series((select min_date from calendar), (select max_date from calendar), '1 day'::interval) as s(d)
join precomputed_interval i on s.d between i.since and i.till
where i.visible_after
order by i.user_id, s.d