英文:
Cursor/Dynamic SQL to execute Postgres Procedure
问题
Here's the translated portion of your text:
我有一个从表中聚合一些数据并将结果放入不同表格以在PowerBI报告中显示的Postgres存储过程。该存储过程每天聚合数据,因此接受“startDate”和“endDate”参数(其中“endDate”始终为“startDate + 1”)。
CREATE OR REPLACE PROCEDURE schema.DailyCalculation(
"startDate" timestamp without time zone,
"endDate" timestamp without time zone)
AS $$
DECLARE
-- 一些声明
BEGIN
-- 做一些事情
END;
$$ LANGUAGE plpgsql;
我现在发现了过去计算数据的错误,并希望为日期范围调用此存储过程。为了将其分成可管理的块,我仍然希望为单一日期范围调用“DailyCalculation”,但创建一个新的存储过程,我可以为其提供更长的日期范围,该存储过程将反复调用“DailyCalculation”,只使用日期范围内的单一日期范围。
举个例子,我想重新计算2023年1月。所以,我想调用类似以下的东西:
CALL schema.RecalculateDailyData('2023-01-01', '2023-01-31');
我希望有效执行以下操作:
CALL schema.DailyCalculation('2023-01-01', '2023-01-02');
CALL schema.DailyCalculation('2023-01-02', '2023-01-03');
CALL schema.DailyCalculation('2023-01-03', '2023-01-04');
...
CALL schema.DailyCalculation('2023-01-30', '2023-01-31');
我已经能够生成一个查询,可以生成动态SQL以实现此效果:
SELECT CONCAT('CALL schema.DailyCalculation(''', '', date_trunc('day', dd)::date, '', '', date_trunc('day', dd)::date + 1, '', '');') FROM generate_series( '2023-01-01'::timestamp, '2023-01-31'::timestamp, '1 day'::interval) dd;
如何遍历此结果集并执行动态SQL查询?
英文:
I have a Postgres procedure that aggregates some data from a table and puts the results in a different table for display on a PowerBI report. The procedure aggregates the data on a daily basis, so accepts a startDate
and endDate
parameter (where endDate
is always startDate + 1
).
CREATE OR REPLACE PROCEDURE schema.DailyCalculation(
"startDate" timestamp without time zone,
"endDate" timestamp without time zone)
AS $$
DECLARE
-- some declarations
BEGIN
-- do some stuff
END;
$$ LANGUAGE plpgsql;
I've now identified an error in the way we calculated data in the past, and want to call this procedure for a date range. To break it into manageable chunks, I still want to call DailyCalculation
for a single day period, but create a new procedure that I can provide with a longer date range that will repeatedly call DailyCalculation
with only single day ranges in that date range.
For arguments' sake, I want to recalculate January 2023. So, I want to call something like:
CALL schema.RecalculateDailyData('2023-01-01', '2023-01-31');
which I want to effectively do the following:
CALL schema.DailyCalculation('2023-01-01', '2023-01-02');
CALL schema.DailyCalculation('2023-01-02', '2023-01-03');
CALL schema.DailyCalculation('2023-01-03', '2023-01-04');
...
CALL schema.DailyCalculation('2023-01-30', '2023-01-31');
I've been able to generate a query that would generate dynamic SQL to this effect:
SELECT CONCAT('CALL schema.DailyCalculation(''', date_trunc('day', dd)::date, ''', ''', date_trunc('day', dd)::date + 1, ''');') FROM generate_series( '2023-01-01'::timestamp, '2023-01-31'::timestamp, '1 day'::interval) dd;
How do I iterate through this resultset, and execute the dynamic SQL query?
答案1
得分: 1
您可以使用函数 generate_series()
来创建感兴趣的每个日期,并在 for
循环中调用您的存储过程。
create or replace procedure DailyCalculation(
startdate timestamp without time zone
, enddate timestamp without time zone
)
language plpgsql
as $$
declare
-- 一些声明
begin
insert into demo(routine_name, start_date, end_date)
values ('Procedure:DailyCalculations', startdate, enddate);
end;
$$;
-- DO block 来调用 DailyCalculations
do $$
declare
sdt record;
begin
for sdt in (select dt
from generate_series ('2023-01-01'::timestamp
, '2023-01-31'::timestamp
, interval '1 day'
) gs(dt)
)
loop
call DailyCalculation(sdt.dt, sdt.dt+interval '1 day');
end loop;
end;
$$;
或者,您可以创建一个函数(返回 Null),而不是存储过程,并通过单个查询完成此操作。
create or replace function DailyCalculation_fn(
startdate timestamp without time zone
, enddate timestamp without time zone
)
returns void
language plpgsql
as $$
declare
-- 一些声明
begin
insert into demo(routine_name, start_date, end_date)
values ('Function DailyCalculation_fn', startdate, enddate);
end;
$$;
select DailyCalculation_fn(dt, dt+interval '1 day')
from generate_series ('2023-01-01'::timestamp
, '2023-01-31'::timestamp
, interval '1 day'
) gs(dt);
然而,备选函数有时依赖副作用,因此有时被认为是不合适的原因。您可以在这里看到每个示例。对于两者都只是插入到一个示例表中。
注意:您指定了存储过程需要两个参数,startDate
和 endDate
,但然后声明结束日期始终是开始日期+1。如果这是必需的,请为什么传递 enddate
,只需让您的存储过程/函数计算结束日期。这样,您可以确保结束日期始终正确。当传递 startDate+2 或 startDate+10 或其他不等于 startDate+1 的值时,您的存储过程会执行什么操作?
1: https://dbfiddle.uk/JnWoOyBN
英文:
You can use the function generate_series()
to create each date of interested and call your procedure in a for
loop.
create or replace procedure DailyCalculation(
startdate timestamp without time zone
, enddate timestamp without time zone
)
language plpgsql
as $$
declare
-- some declarations
begin
insert into demo(routine_name, start_date, end_date)
values ('Procedure:DailyCalculations', startdate,enddate);
end;
$$;
-- DO block to call DailyCalculations
do $$
declare
sdt record;
begin
for sdt in (select dt
from generate_series ( '2023-01-01'::timestamp
, '2023-01-31'::timestamp
, interval '1 day'
) gs(dt)
)
loop
call DailyCalculation(sdt.dt, sdt.dt+interval '1 day');
end loop;
end;
$$;
Alternatively you can create a Function (returns Null) instead of a Procedure and accomplish this with a single query.
create or replace function DailyCalculation_fn(
startdate timestamp without time zone
, enddate timestamp without time zone
)
returns void
language plpgsql
as $$
declare
-- some declarations
begin
insert into demo(routine_name, start_date, end_date)
values ('Function DailyCalculation_fn', startdate,enddate);
end;
$$;
select DailyCalculation_fn(dt, dt+interval '1 day')
from generate_series ('2023-01-01'::timestamp
, '2023-01-31'::timestamp
, interval '1 day'
) gs(dt);
The alternative function however does rely side effects and is sometimes considered inappropriate for that reason.
See demo for each here. For demo both just insert into a demo table.
NOTE: You specified tour procedure needs 2 parameters, startDate
and endDate
, but then declare that end date is always be start+1. If this is required, why pass enddate
just let your procedure/function calculate the end date. That way you ensure the end date is always correct. What does your Procedure do when startDate+2 or startDate+10 or anything other than startdate+1 is passed.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论