如何在 postgresql 中的日期之间生成间隔行
How generate gap rows between dates in postgresql
我有一个存储付款的 table。我需要合并付款日期和未付款日期。
所以我会有这样的东西:
DeudaId Date Value
1 2016-01-01 0 <- This come from a table
1 2016-01-02 [=10=] <- This was calculated
1 2016-01-03 [=10=] <- This was calculated
1 2016-01-04 0 <- This come from a table
我有这个必要的解决方案,但对我来说太慢了:
CREATE OR REPLACE FUNCTION build_dates2()
RETURNS TABLE (id INTEGER, cobrador_id INTEGER, fecha DATE)
LANGUAGE plpgsql
IMMUTABLE STRICT
AS $function$DECLARE min_date DATE;
DECLARE
r RECORD;
fecha RECORD;
BEGIN
for r in (SELECT * FROM recaudo_deuda) LOOP
for fecha in (select toFecha(r.fecha) + s.a AS dates from generate_series(0, r.plazo) as s(a)) LOOP
return query VALUES ( r.id, r.cobrador_id, fecha.dates);
END LOOP;
END LOOP;
END
$function$;
SELECT * from build_dates2()
我知道我可以创建另一个 table 并使用触发器存储数据。我想知道是否存在一种即时执行此操作的有效方法。
我也尝试用 recaudo_deuda table 的 min/max 值生成一个日期列表,但后来我看不出如何从中构建结果:
CREATE OR REPLACE FUNCTION public.build_dates()
RETURNS TABLE(dates date)
LANGUAGE plpgsql
IMMUTABLE STRICT
AS $function$
DECLARE min_date DATE;
DECLARE dias INTEGER;
BEGIN
SELECT min(fecha), extract(DAY from max(fecha) - min(fecha))
from recaudo_deuda INTO min_date, dias;
RETURN QUERY select min_date + s.a AS dates from generate_series(0,dias) as s(a);
END
$function$
您可以使用一个 SQL 语句来完成此操作,如下所示:
select d.deudaid, s.a as date, coalesce(d.value, 0) as value
from (
select min(fecha), max(fecha)
from recaudo_deuda
) m (mi, mx)
cross join lateral generate_series(m.mi, m.mx, interval '1' day) as s(a)
left join recaudo_deuda d on d.fecha = s.a::date
order by s.a;
有点疯狂的解决方案。
简单示例:
with t(x) as (values(1),(2),(5),(10),(11))
select
x,
generate_series(x, coalesce(lead(x) over (order by x) - 1, x)) as x_gaps,
x = generate_series(x, coalesce(lead(x) over (order by x) - 1, x)) as x_real
from t;
转换为您的情况可能是(不确定我对列名的准确程度):
select
deudaid,
generate_series(fecha, coalesce(lead(fecha) over (order by fecha) - '1d', fecha), '1d') as fecha,
(fecha = generate_series(fecha, coalesce(lead(fecha) over (order by fecha) - '1d', fecha), '1d'))::int * value as value
from
recaudo_deuda;
我有一个存储付款的 table。我需要合并付款日期和未付款日期。
所以我会有这样的东西:
DeudaId Date Value
1 2016-01-01 0 <- This come from a table
1 2016-01-02 [=10=] <- This was calculated
1 2016-01-03 [=10=] <- This was calculated
1 2016-01-04 0 <- This come from a table
我有这个必要的解决方案,但对我来说太慢了:
CREATE OR REPLACE FUNCTION build_dates2()
RETURNS TABLE (id INTEGER, cobrador_id INTEGER, fecha DATE)
LANGUAGE plpgsql
IMMUTABLE STRICT
AS $function$DECLARE min_date DATE;
DECLARE
r RECORD;
fecha RECORD;
BEGIN
for r in (SELECT * FROM recaudo_deuda) LOOP
for fecha in (select toFecha(r.fecha) + s.a AS dates from generate_series(0, r.plazo) as s(a)) LOOP
return query VALUES ( r.id, r.cobrador_id, fecha.dates);
END LOOP;
END LOOP;
END
$function$;
SELECT * from build_dates2()
我知道我可以创建另一个 table 并使用触发器存储数据。我想知道是否存在一种即时执行此操作的有效方法。
我也尝试用 recaudo_deuda table 的 min/max 值生成一个日期列表,但后来我看不出如何从中构建结果:
CREATE OR REPLACE FUNCTION public.build_dates()
RETURNS TABLE(dates date)
LANGUAGE plpgsql
IMMUTABLE STRICT
AS $function$
DECLARE min_date DATE;
DECLARE dias INTEGER;
BEGIN
SELECT min(fecha), extract(DAY from max(fecha) - min(fecha))
from recaudo_deuda INTO min_date, dias;
RETURN QUERY select min_date + s.a AS dates from generate_series(0,dias) as s(a);
END
$function$
您可以使用一个 SQL 语句来完成此操作,如下所示:
select d.deudaid, s.a as date, coalesce(d.value, 0) as value
from (
select min(fecha), max(fecha)
from recaudo_deuda
) m (mi, mx)
cross join lateral generate_series(m.mi, m.mx, interval '1' day) as s(a)
left join recaudo_deuda d on d.fecha = s.a::date
order by s.a;
有点疯狂的解决方案。
简单示例:
with t(x) as (values(1),(2),(5),(10),(11))
select
x,
generate_series(x, coalesce(lead(x) over (order by x) - 1, x)) as x_gaps,
x = generate_series(x, coalesce(lead(x) over (order by x) - 1, x)) as x_real
from t;
转换为您的情况可能是(不确定我对列名的准确程度):
select
deudaid,
generate_series(fecha, coalesce(lead(fecha) over (order by fecha) - '1d', fecha), '1d') as fecha,
(fecha = generate_series(fecha, coalesce(lead(fecha) over (order by fecha) - '1d', fecha), '1d'))::int * value as value
from
recaudo_deuda;