postgresql 连续期间的差距

mrphzbgm  于 2023-05-28  发布在  PostgreSQL
关注(0)|答案(2)|浏览(106)

我有一张table:
| 用户id|类型|日期|
| - -----|- -----|- -----|
| 一个|质数|2022 - 05 - 31 - 2022 - 05 - 31 - 2022 - 2023 - 05 - 21|
| 一个|平常的|2022 - 06 - 30 - 2022 - 2023 - 2023 - 2023 - 2024 - 2025 - 2025 - 2025 - 2026 - 2026 - 2026 - 2026 - 2026 - 2026 - 2026 - 2026 - 2026 - 2026 - 2026 - 2026 - 2026 - 2026 - 2026 - 2026 - 2026 - 2026 - 2026 - 2026 - 2026 - 2026 - 2026 - 2026 - 2026 - 2026 - 2026 - 2026 - 2026 - 2026 - 2026 - 2026 - 2026 - 2026 - 2026 - 2026 - 2026 - 2026 - 2026 - 2026|
| 一个|平常的|2022 - 07 - 31 - 2022 - 07 - 21 - 22|
| 一个|平常的|2022 - 09 - 31 - 2022 - 09 - 31|
我需要得到一个按user_id、类型和有效期分组的表。主要的困难是周期可能不是连续的(它们之间的距离超过1个月):
Otput应为:
| 用户id|类型|开始月份|月末|
| - -----|- -----|- -----|- -----|
| 一个|质数|2022 - 05年|2022 - 05年|
| 一个|平常的|2022 - 06年|2022 - 07|
| 一个|平常的|2022 - 09| 2022 - 09|

hjqgdpho

hjqgdpho1#

在另一种方法中,我们可以使用row_number函数如下:

select user_id, type, min(date_) start_month, max(date_) end_month
from(
  select *,
    date_ - interval '1 month' * row_number() over (partition by user_id, type order by date_) grp
  from table_name
) t
group by user_id, type, to_char(grp, 'YYYY-MM')
order by user_id, type, start_month

demo

hrirmatl

hrirmatl2#

这是一个典型的缺口和孤岛问题,您需要构建一个更精细的分区。为了做到这一点,您:

  • 创建一个标志来了解何时更改分区
  • 计算标志的运行和以创建实际的分区
  • 应用聚合
WITH cte AS (
    SELECT *, 
           CASE WHEN LEAD(date) OVER(PARTITION BY user_id, type ORDER BY date) > date + INTERVAL '1 MONTH' THEN 0 ELSE 1 END AS changepart
    FROM tab
), cte2 AS (
    SELECT *,
           SUM(changepart) OVER(PARTITION BY user_id, type ORDER BY date) AS parts
    FROM cte
)
SELECT user_id, 
       type, 
       MIN(date) AS start_dt,
       MAX(date) AS end_dt
FROM cte2
GROUP BY user_id,
         type, 
         parts
    • 输出**:

| 用户id|类型|开始_dt| end_dt|
| - -----|- -----|- -----|- -----|
| 一个|质数|2022 - 05 - 31 - 2022 - 05 - 31 - 2022 - 2023 - 05 - 21| 2022 - 05 - 31 - 2022 - 05 - 31 - 2022 - 2023 - 05 - 21|
| 一个|平常的|2022 - 06 - 30 - 2022 - 2023 - 2023 - 2023 - 2024 - 2025 - 2025 - 2025 - 2026 - 2026 - 2026 - 2026 - 2026 - 2026 - 2026 - 2026 - 2026 - 2026 - 2026 - 2026 - 2026 - 2026 - 2026 - 2026 - 2026 - 2026 - 2026 - 2026 - 2026 - 2026 - 2026 - 2026 - 2026 - 2026 - 2026 - 2026 - 2026 - 2026 - 2026 - 2026 - 2026 - 2026 - 2026 - 2026 - 2026 - 2026 - 2026 - 2026| 2022 - 07 - 31 - 2022 - 07 - 21 - 22|
| 一个|平常的|2022 - 09 - 30 - 2022 - 09 - 30| 2022 - 09 - 30 - 2022 - 09 - 30|
查看演示here

    • 注意**:日期不能只有年和月。日期总是由年、月和日组成。最好的情况是,您的“* start_dt ”和“ end_dt *”可以使用DATE_TRUNC('MONTH', your_date)转换为该月的第一天。

相关问题