postgresql 计算几个时间差给予不同的输出

toiithl6  于 2023-03-08  发布在  PostgreSQL
关注(0)|答案(1)|浏览(117)

我有下表:
| 实体标识|时间_c|下次_时间_c|
| - ------|- ------|- ------|
| 1个|'2023年1月2日10时34分36秒'|'2023年1月10日15时12分24秒'|
| 第二章|'2023年3月1日16时10分12秒'|'2023年3月20日22时47分59秒'|
我的目标是计算time_cnext_time_c之间的间隔(不包括星期六和星期日)以及完整间隔。
我提出以下查询:

WITH parms (entity_id, start_date, end_date) AS
(
    SELECT 
        entity_id,
        time_c::timestamp,
        next_time_c::timestamp
    FROM 
        test_c
), weekend_days (wkend) AS 
(
    SELECT 
        SUM(CASE WHEN EXTRACT(isodow FROM d) IN (6, 7) THEN 1 ELSE 0 END) 
    FROM 
        parms 
    CROSS JOIN 
        generate_series(start_date, end_date, interval '1 day') dn(d)
)
SELECT 
    entity_id AS "ID",
    CONCAT(
        extract(day from diff), ' days ', 
        extract( hours from diff)   , ' hours ', 
        extract( minutes from diff) , ' minutes ', 
        extract( seconds from diff)::int , ' seconds '
    ) AS "Duration (excluding saturday and sunday)",
    justify_interval(end_date::timestamp - start_date::timestamp) AS "Duration full"
FROM (
    SELECT 
        start_date,
        end_date,
        entity_id,
        (end_date-start_date) - (wkend * interval '1 day') AS diff
    FROM parms 
    JOIN weekend_days ON true
) sq;

当我的表中只有1行时,它工作得很好,当有1行以上时,结果是错误的。
1行:
| 识别号|持续时间(不包括周六和周日)|持续时间已满|
| - ------|- ------|- ------|
| 1个|6天4小时37分48秒|{"天":8,"小时":4,"分钟":37,"秒":48}|
| 识别号|持续时间(不包括周六和周日)|持续时间已满|
| - ------|- ------|- ------|
| 第二章|13天6小时37分47秒|{"天":19,"小时":6,"分钟":37,"秒":47}|
2行:
| 识别号|持续时间(不包括周六和周日)|持续时间已满|
| - ------|- ------|- ------|
| 1个|0天4小时37分48秒|{"天":8,"小时":4,"分钟":37,"秒":48}|
| 第二章|11天6小时37分47秒|{"天":19,"小时":6,"分钟":37,"秒":47}|
为什么计算多行时结果为false?
演示:https://www.db-fiddle.com/f/mDCS6cSwT1hbvit2WLYZbc/0

rsaldnfx

rsaldnfx1#

应分别计算每个entity_id的周末天数:

...
    SELECT 
        entity_id,
        SUM(case when extract(isodow from d) in (6, 7) then 1 else 0 end) 
    FROM 
        parms
    CROSS JOIN 
        generate_series(start_date, end_date, interval '1 day') dn(d)
    GROUP BY entity_id
...

检查Db-Fiddle.中的完整查询
更新。上述解决方案假定entity_id是唯一的,因为它用于标识各个行。如果没有唯一的列,则可以使用定制函数或横向子查询。这是第二个选项:

select
    entity_id as "ID",
    concat(
        extract(day from diff), ' days ', 
        extract(hours from diff)   , ' hours ', 
        extract(minutes from diff) , ' minutes ', 
        extract(seconds from diff)::int , ' seconds '
    ) as "Duration (excluding saturday and sunday)",
    justify_interval(end_date - start_date) as "Duration full"
from (
    select 
        entity_id,
        time_c as start_date,
        next_time_c as end_date,
        (next_time_c - time_c) - weekend_days as diff
    from test_c,
    lateral (
        select sum((extract(isodow from d) in (6, 7))::int)* interval '1 day' as weekend_days
        from generate_series(time_c, next_time_c, '1 day') dn(d)
    ) wd
) sq;

Db<>Fiddle.中检查

相关问题