提取按月postgresql分组的日期范围的天数
extract days of daterange grouped by month postresql
我的 OrderHistory table 中有一个 pickupDate 和 returnDate。我想按月提取所有 OrderHistory 条目的租赁天数 grouped/ordered。 cte 似乎是解决方案,但我不知道如何在我的查询中实现它,因为我看到的 cte 指的是它们自己,上面写着“FROM cte”。
我试过这样的事情:
SELECT
SUM((EXTRACT (DAY FROM("OrderHistory"."returnDate")-("OrderHistory"."pickupDate")))) as traveltime
, to_char("OrderHistory"."pickupDate"::date, 'YYYY-MM') as M
FROM
"OrderHistory"
GROUP BY
M
ORDER BY
M
但结果不会将预订拆分为两个月(例如 pickupDate=2022 年 3 月 27 日和 returnDate=2022 年 4 月 3 日),但会将整个 7 天分配给 3 月,因为返回日期在其中.它应该在 3 月显示 4 天,在 4 月显示 3 天。
对于这个可能非常愚蠢的问题,我深表歉意,但我是初学者。 (顺便说一句,我的代码是用 postgresql 编写的)
PostgreSQL naming conventions
Are PostgreSQL column names case-sensitive?
use legal, lower-case names exclusively so double-quoting is not
needed.
最终结果 db fiddle
添加日期范围列。
alter table order_history add column date_ranges daterange;
更新 order_history
with a(m_begin, m_end, pickup_date) as
(select date_trunc('month', pickup_date)::date,
(date_trunc('month', pickup_date) + interval '1 month - 1 day')::date,
pickup_date from order_history)
update order_history set date_ranges =
daterange(a.m_begin, a.m_end,'[]') from a
where a.pickup_date = order_history.pickup_date;
然后最终查询:
WITH A AS(
select
pickup_date,
return_date,
return_date - pickup_date as total,
case when return_date <@ date_ranges then (return_date - pickup_date)
else ( date_trunc('month', pickup_date) + interval '1 month - 1 day')::date - pickup_date
end partial_mth
from order_history),
b as (SELECT *, a.total - partial_mth parital_not_mth FROM a)
select *,
case when to_char(pickup_date,'YYYY-MM') = to_char(return_date,'YYYY-MM')
then
sum(partial_mth) over(partition by to_char(pickup_date,'YYYY-MM')) +
sum(parital_not_mth) over (partition by to_char(return_date,'YYYY-MM'))
else sum(partial_mth) over(partition by to_char(pickup_date,'YYYY-MM'))
end
from b;
在尝试不同的方法后,我认为我找到了我的问题的最佳答案,我想与社区分享:
WITH hier as (
SELECT
"OrderHistory"."pickupDate" as start_date
, "OrderHistory"."returnDate" as end_date
, to_char("OrderHistory"."pickupDate"::date, 'YYYY-MM') as M
FROM
"OrderHistory"
GROUP BY
1, 2, 3
ORDER BY
3
), calendar as (
select date '2022-01-01' + (n || ' days')::interval calendar_date
from generate_series(0, 365) n
)
select
to_char(calendar_date::date, 'YYYY-MM')
, count(*) as tage_gebucht
from calendar
inner join hier on calendar.calendar_date between start_date and end_date
where calendar_date between '2022-01-01' and '2022-12-31'
group by 1
order by 1;
我认为这是我想到的最简单的解决方案。
我的 OrderHistory table 中有一个 pickupDate 和 returnDate。我想按月提取所有 OrderHistory 条目的租赁天数 grouped/ordered。 cte 似乎是解决方案,但我不知道如何在我的查询中实现它,因为我看到的 cte 指的是它们自己,上面写着“FROM cte”。
我试过这样的事情:
SELECT
SUM((EXTRACT (DAY FROM("OrderHistory"."returnDate")-("OrderHistory"."pickupDate")))) as traveltime
, to_char("OrderHistory"."pickupDate"::date, 'YYYY-MM') as M
FROM
"OrderHistory"
GROUP BY
M
ORDER BY
M
但结果不会将预订拆分为两个月(例如 pickupDate=2022 年 3 月 27 日和 returnDate=2022 年 4 月 3 日),但会将整个 7 天分配给 3 月,因为返回日期在其中.它应该在 3 月显示 4 天,在 4 月显示 3 天。
对于这个可能非常愚蠢的问题,我深表歉意,但我是初学者。 (顺便说一句,我的代码是用 postgresql 编写的)
PostgreSQL naming conventions
Are PostgreSQL column names case-sensitive?
use legal, lower-case names exclusively so double-quoting is not needed.
最终结果 db fiddle
添加日期范围列。
alter table order_history add column date_ranges daterange;
更新 order_history
with a(m_begin, m_end, pickup_date) as
(select date_trunc('month', pickup_date)::date,
(date_trunc('month', pickup_date) + interval '1 month - 1 day')::date,
pickup_date from order_history)
update order_history set date_ranges =
daterange(a.m_begin, a.m_end,'[]') from a
where a.pickup_date = order_history.pickup_date;
然后最终查询:
WITH A AS(
select
pickup_date,
return_date,
return_date - pickup_date as total,
case when return_date <@ date_ranges then (return_date - pickup_date)
else ( date_trunc('month', pickup_date) + interval '1 month - 1 day')::date - pickup_date
end partial_mth
from order_history),
b as (SELECT *, a.total - partial_mth parital_not_mth FROM a)
select *,
case when to_char(pickup_date,'YYYY-MM') = to_char(return_date,'YYYY-MM')
then
sum(partial_mth) over(partition by to_char(pickup_date,'YYYY-MM')) +
sum(parital_not_mth) over (partition by to_char(return_date,'YYYY-MM'))
else sum(partial_mth) over(partition by to_char(pickup_date,'YYYY-MM'))
end
from b;
在尝试不同的方法后,我认为我找到了我的问题的最佳答案,我想与社区分享:
WITH hier as (
SELECT
"OrderHistory"."pickupDate" as start_date
, "OrderHistory"."returnDate" as end_date
, to_char("OrderHistory"."pickupDate"::date, 'YYYY-MM') as M
FROM
"OrderHistory"
GROUP BY
1, 2, 3
ORDER BY
3
), calendar as (
select date '2022-01-01' + (n || ' days')::interval calendar_date
from generate_series(0, 365) n
)
select
to_char(calendar_date::date, 'YYYY-MM')
, count(*) as tage_gebucht
from calendar
inner join hier on calendar.calendar_date between start_date and end_date
where calendar_date between '2022-01-01' and '2022-12-31'
group by 1
order by 1;
我认为这是我想到的最简单的解决方案。