postgresql Postgres -对表进行分区

khbbv19g  于 2022-11-29  发布在  PostgreSQL
关注(0)|答案(2)|浏览(182)

如何划分下表的代码。日期和状态已给出,应添加分区列。列组仅用于说明组的开始和结束位置。最后,我喜欢做一些分析,例如每个组的过程需要多长时间。
用文字却不知道转换成代码:状态“已批准”始终定义结束。只有“批准”之后的“打开”定义开始。其他“打开”不相关。
| 日期|状态|分组|分区|
| - -|- -|- -|- -|
| 二零二二年十月一日|打开的|第1组启动|一个|
| 二○二二年十月二日|等待||一个|
| 二零二二年十月三日|打开的||一个|
| 二零二二年十月四日|等待||一个|
| 二零二二年十月五日|已核准|组1结束|一个|
| 二零二二年十月七日|打开的|第2组开始|2个|
| 二○二二年十月八日|等待||2个|
| 二零二二年十月九日|打开的||2个|
| 二〇二二年十月十日|等待||2个|
| 二零二二年十月十一日|打开的||2个|
| 二零二二年十月十二日|等待||2个|
| 二零二二年十月十五日|已核准|组2结束|2个|
| 二零二二年十月十七日|打开的|第3组启动|三个|
| 二零二二年十月二十日|等待||三个|
谢谢你的解决方案。工作很好:-)很抱歉没有使用正确的表达式。如果组比分区更好,甚至更好...
我们能把它弄复杂一点吗?
表中的这种模式适用于多个父记录。因此,实际上还有一个附加列“父ID”。下表是父ID A的示例。还有更多的父记录。
如何按父ID添加附加分组?在每个新父ID处,计数从1重新开始

f2uvfpb9

f2uvfpb91#

假设您有前两个数据行,并想要衍生后两个数据行,请将此视为间隙与岛的问题:

with groups as (  -- Assign partitions
  select *, 
         coalesce(
           sum(case when status = 'approved' then 1 else 0 end) 
             over (order by date rows between unbounded preceding 
                                          and 1 preceding),
           0
         ) + 1 as partition
    from do_part
)
select date, status, 
       case   -- Construct text descriptions
         when partition != coalesce(lead(partition) over w, partition) 
           then format('Group %s Ends', partition)
         when partition = lag(partition) over w
           then '' 
         else format('Group %s Starts', partition)
       end as "group",
       partition
  from groups
window w as (order by date);

Fiddle here

ar7v8xwq

ar7v8xwq2#

demo基于(Mike Organek)的小提琴。
想法:带distinct on的左连接可以正确地剪切组。

SELECT DISTINCT ON (date,status)
    date,
    status,
    coalesce(date_d, CURRENT_DATE) AS date_end
FROM
    do_part t
    LEFT JOIN (
        SELECT
            date AS date_d
        FROM
            do_part
        WHERE
            status = 'approved'
        ORDER BY
            date) s ON s.date_d >= t.date
ORDER BY
    date,status,
    date_d;

最终查询(可简化):

WITH cte AS (
    SELECT DISTINCT ON (date,
        status)
        date,
        status,
        coalesce(date_d, CURRENT_DATE) AS date_end
    FROM
        do_part t
        LEFT JOIN (
            SELECT
                date AS date_d
            FROM
                do_part
            WHERE
                status = 'approved'
            ORDER BY
                date) s ON s.date_d >= t.date
        ORDER BY
            date,
            status,
            date_d
),
cte1 AS (
    SELECT
        *,
        date_end - first_value(date) OVER (PARTITION BY date_end ORDER BY date) AS date_gap,
    dense_rank() OVER (ORDER BY date_end),
    CASE WHEN (date = first_value(date) OVER (PARTITION BY date_end ORDER BY date)) THEN
        'group begin'
    WHEN (status = 'approved') THEN
        'group end '
    ELSE
        NULL
    END AS grp
FROM
    cte
)
SELECT
    *,
    CASE WHEN grp IS NOT NULL THEN
        grp || dense_rank::text
    END
FROM
    cte1;

相关问题