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

huangapple go评论112阅读模式
英文:

Calculate several timedifference give different output

问题

以下是您要翻译的代码部分:

  1. I have the following table :
  2. | entity_id | time_c | next_time_c |
  3. |:---------:|-----------------------|-----------------------|
  4. | 1 | '2023-01-02 10:34:36' | '2023-01-10 15:12:24' |
  5. | 2 | '2023-03-01 16:10:12' | '2023-03-20 22:47:59' |
  6. My goal is to calculate the interval between `time_c` and `next_time_c` without Saturday and Sunday and the full interval.
  7. I come up with the following query :
  8. WITH parms (entity_id, start_date, end_date) AS
  9. (
  10. SELECT
  11. entity_id,
  12. time_c::timestamp,
  13. next_time_c::timestamp
  14. FROM
  15. test_c
  16. ), weekend_days (wkend) AS
  17. (
  18. SELECT
  19. SUM(CASE WHEN EXTRACT(isodow FROM d) IN (6, 7) THEN 1 ELSE 0 END)
  20. FROM
  21. parms
  22. CROSS JOIN
  23. generate_series(start_date, end_date, interval '1 day') dn(d)
  24. )
  25. SELECT
  26. entity_id AS "ID",
  27. CONCAT(
  28. extract(day from diff), ' days ',
  29. extract( hours from diff) , ' hours ',
  30. extract( minutes from diff) , ' minutes ',
  31. extract( seconds from diff)::int , ' seconds '
  32. ) AS "Duration (excluding saturday and sunday)",
  33. justify_interval(end_date::timestamp - start_date::timestamp) AS "Duration full"
  34. FROM (
  35. SELECT
  36. start_date,
  37. end_date,
  38. entity_id,
  39. (end_date-start_date) - (wkend * interval '1 day') AS diff
  40. FROM parms
  41. JOIN weekend_days ON true
  42. ) sq;
  43. It works well when I have only 1 row in my table. When there is more than 1 row, the result is wrong.
  44. With 1 row :
  45. | ID | Duration (excluding saturday and sunday) | Duration full
  46. | ----| ---------------------------------------- | -----------------------------------------------
  47. | 1 | 6 days 4 hours 37 minutes 48 seconds | {"days":8,"hours":4,"minutes":37,"seconds":48} |
  48. | ID | Duration (excluding saturday and sunday) | Duration full
  49. | ----| ---------------------------------------- | -----------------------------------------------
  50. | 2 | 13 days 6 hours 37 minutes 47 seconds | {"days":19,"hours":6,"minutes":37,"seconds":47}
  51. With 2 rows :
  52. | ID | Duration (excluding saturday and sunday) | Duration full
  53. | ----| ---------------------------------------- | -----------------------------------------------
  54. | 1 | 0 days 4 hours 37 minutes 48 seconds | {"days":8,"hours":4,"minutes":37,"seconds":48}
  55. | 2 | 11 days 6 hours 37 minutes 47 seconds | {"days":19,"hours":6,"minutes":37,"seconds":47}
  56. Why the result is false when calculating several rows ?
  57. Demo : https://www.db-fiddle.com/f/mDCS6cSwT1hbvit2WLYZbc/0

希望这对您有所帮助。如果您需要进一步的解释或帮助,请随时告诉我。

英文:

I have the following table :

entity_id time_c next_time_c
1 '2023-01-02 10:34:36' '2023-01-10 15:12:24'
2 '2023-03-01 16:10:12' '2023-03-20 22:47:59'

My goal is to calculate the interval between time_c and next_time_c without Saturday and Sunday and the full interval.

I come up with the following query :

  1. WITH parms (entity_id, start_date, end_date) AS
  2. (
  3. SELECT
  4. entity_id,
  5. time_c::timestamp,
  6. next_time_c::timestamp
  7. FROM
  8. test_c
  9. ), weekend_days (wkend) AS
  10. (
  11. SELECT
  12. SUM(CASE WHEN EXTRACT(isodow FROM d) IN (6, 7) THEN 1 ELSE 0 END)
  13. FROM
  14. parms
  15. CROSS JOIN
  16. generate_series(start_date, end_date, interval '1 day') dn(d)
  17. )
  18. SELECT
  19. entity_id AS "ID",
  20. CONCAT(
  21. extract(day from diff), ' days ',
  22. extract( hours from diff) , ' hours ',
  23. extract( minutes from diff) , ' minutes ',
  24. extract( seconds from diff)::int , ' seconds '
  25. ) AS "Duration (excluding saturday and sunday)",
  26. justify_interval(end_date::timestamp - start_date::timestamp) AS "Duration full"
  27. FROM (
  28. SELECT
  29. start_date,
  30. end_date,
  31. entity_id,
  32. (end_date-start_date) - (wkend * interval '1 day') AS diff
  33. FROM parms
  34. JOIN weekend_days ON true
  35. ) sq;

It works well when I have only 1 row in my table. When there is more than 1 row, the result is wrong.

With 1 row :

ID Duration (excluding saturday and sunday) Duration full
1 6 days 4 hours 37 minutes 48 seconds {"days":8,"hours":4,"minutes":37,"seconds":48}
ID Duration (excluding saturday and sunday) Duration full
2 13 days 6 hours 37 minutes 47 seconds {"days":19,"hours":6,"minutes":37,"seconds":47}

With 2 rows :

ID Duration (excluding saturday and sunday) Duration full
1 0 days 4 hours 37 minutes 48 seconds {"days":8,"hours":4,"minutes":37,"seconds":48}
2 11 days 6 hours 37 minutes 47 seconds {"days":19,"hours":6,"minutes":37,"seconds":47}

Why the result is false when calculating several rows ?

Demo : https://www.db-fiddle.com/f/mDCS6cSwT1hbvit2WLYZbc/0

答案1

得分: 1

你应该分别为每个 entity_id 计算周末天数:

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

Db-Fiddle中检查完整查询。


更新。上述解决方案假设 entity_id 是唯一的,因为它用于标识单个行。如果没有唯一的列,可以使用自定义函数或lateral子查询。这是第二个选项:

  1. select
  2. entity_id as "ID",
  3. concat(
  4. extract(day from diff), ' days ',
  5. extract(hours from diff) , ' hours ',
  6. extract(minutes from diff) , ' minutes ',
  7. extract(seconds from diff)::int , ' seconds '
  8. ) as "Duration (excluding saturday and sunday)",
  9. justify_interval(end_date - start_date) as "Duration full"
  10. from (
  11. select
  12. entity_id,
  13. time_c as start_date,
  14. next_time_c as end_date,
  15. (next_time_c - time_c) - weekend_days as diff
  16. from test_c,
  17. lateral (
  18. select sum((extract(isodow from d) in (6, 7))::int)* interval '1 day' as weekend_days
  19. from generate_series(time_c, next_time_c, '1 day') dn(d)
  20. ) wd
  21. ) sq;

Db<>Fiddle中检查。

英文:

You should calculate weekend days for each entity_id separately:

  1. ...
  2. SELECT
  3. entity_id,
  4. SUM(case when extract(isodow from d) in (6, 7) then 1 else 0 end)
  5. FROM
  6. parms
  7. CROSS JOIN
  8. generate_series(start_date, end_date, interval &#39;1 day&#39;) dn(d)
  9. GROUP BY entity_id
  10. ...

Check the full query in Db-Fiddle.


Update. The above solution assumes that entity_id is unique as it is used to identify individual rows. If you do not have a unique column you can use a custom function or a lateral subquery. This is the second option:

  1. select
  2. entity_id as &quot;ID&quot;,
  3. concat(
  4. extract(day from diff), &#39; days &#39;,
  5. extract(hours from diff) , &#39; hours &#39;,
  6. extract(minutes from diff) , &#39; minutes &#39;,
  7. extract(seconds from diff)::int , &#39; seconds &#39;
  8. ) as &quot;Duration (excluding saturday and sunday)&quot;,
  9. justify_interval(end_date - start_date) as &quot;Duration full&quot;
  10. from (
  11. select
  12. entity_id,
  13. time_c as start_date,
  14. next_time_c as end_date,
  15. (next_time_c - time_c) - weekend_days as diff
  16. from test_c,
  17. lateral (
  18. select sum((extract(isodow from d) in (6, 7))::int)* interval &#39;1 day&#39; as weekend_days
  19. from generate_series(time_c, next_time_c, &#39;1 day&#39;) dn(d)
  20. ) wd
  21. ) sq;

Check it in Db<>Fiddle.

huangapple
  • 本文由 发表于 2023年3月7日 21:08:44
  • 转载请务必保留本文链接:https://go.coder-hub.com/75662395.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定