在过程中执行动态插入

问题描述 投票:0回答:2

我是 Postgres 新手,正在尝试创建将多个表中的数据插入到单个表中的代码。

所有源表的名称都以“B3_HIST_”开头,仅年份不同(它们的命名范围为“B3_HIST_2015”到“B3_HIST_2023”)。

我使用 3 个变量,连接名称并在循环中使用它们,如下所示:

create or replace procedure dbo.SP_B3_HIST ()
language plpgsql
AS $$
declare
    nametab TEXT := 'dbo.B3_HIST_';
    startyr INTEGER := 2015;
    lastyr INTEGER := 2023;
begin
    while startyr <= lastyr  loop

        INSERT INTO TEMP1 SELECT * FROM (nametab || startyr )
        startyr = startyr  + 1
    END LOOP;
END; $$

问题:

ERROR: string between dollars did not end in or near "$$
declare
    nametab TEXT := 'dbo.B3_HIST_'"
LINE 3: AS$$
^

如何正确执行此操作?

postgresql plpgsql dynamic-sql
2个回答
1
投票

可以循环为每个源表运行单独的

INSERT
。 (就像大表和每个表后面的
COMMIT
?)当然需要正确的语法,就像评论中指出的Islingre...

通常,构建单个语句(使用纯 SQL)并执行更简单、更快:

CREATE OR REPLACE PROCEDURE dbo.sp_b3_hist()
  LANGUAGE plpgsql AS
$proc$
DECLARE
   nametab text := 'dbo.b3_hist_';  -- lower case
   startyr int := 2015;
   lastyr  int := 2023;
BEGIN
-- RAISE NOTICE '%', (  -- debug first?
   EXECUTE (
   SELECT E'INSERT INTO temp1 \n'
       || string_agg('TABLE ' || nametab || g, E'\nUNION ALL ')
   FROM   generate_series(startyr, lastyr) g
   );
END
$proc$;

CALL dbo.sp_b3_hist();

相关:

如果是一次性操作,请使用

DO
命令而不是持久化过程。

或者在 psql 中使用

\gexec

参见:

避免在 Postgres 中混合大小写标识符,让您的生活更轻松。


0
投票

我只是按照你的解决方案。对存储过程 INSERT 语句进行细微更改。 问题在于存储过程中表的动态名称。有不同的方法可以解决它。我使用 quote_ident() 函数来解决该问题。根据 postgresql 的文档,它是:

quote_ident(文本)→文本

返回适当引用的给定字符串,以用作 SQL 语句字符串中的标识符。仅在必要时添加引号(即,如果字符串包含非标识符字符或大小写折叠)。嵌入的引号适当加倍 quote_ident('Foo bar') → "Foo bar"

让我们开始实际工作吧。

  1. 创建表(3)并附加测试数据
CREATE TABLE IF NOT EXISTS public.B3_HIST_2015
(
    TranDate Date,
    amount numeric(12,2)
);
INSERT INTO public.B3_HIST_2015(
    TranDate, Amount)
    VALUES ('01-Jan-2015', 2000), ('01-Feb-2015', 3000), ('01-Mar-2015', 4000);
    
CREATE TABLE IF NOT EXISTS public.B3_HIST_2016
(
    TranDate Date,
    amount numeric(12,2)
);
INSERT INTO public.B3_HIST_2016(
    TranDate, Amount)
    VALUES ('02-Apr-2016', 2000), ('03-May-2016', 3000), ('04-Jun-2016', 4000);

CREATE TABLE IF NOT EXISTS public.B3_HIST_2017
(
    TranDate Date,
    amount numeric(12,2)
);
INSERT INTO public.B3_HIST_2017(
    TranDate, Amount)
    VALUES ('12-Jul-2017', 2500), ('13-Aug-2017', 3007), ('14-Sep-2017', 4060);
    
CREATE TABLE IF NOT EXISTS public.TEMP1
(
    TranDate Date,
    amount numeric(12,2)
);
  1. 创建存储过程
create or replace procedure public.SP_B3_HIST ()
language plpgsql
AS $$
declare
    nametab TEXT := 'b3_hist_';
    temptab TEXT :='';
    startyr INTEGER := 2015;
    lastyr INTEGER := 2017;
begin

    while startyr <= lastyr  loop
        temptab = CONCAT(nametab, startyr);
        execute 'INSERT INTO TEMP1(TranDate, Amount) (SELECT TranDate, Amount FROM ' || quote_ident(temptab) || ')';
        startyr = startyr  + 1;
    END LOOP;

END; $$;
  1. 最终调用程序执行
call public.SP_B3_HIST ();
  1. 检查表temp1中的数据
SELECT * FROM temp1;

谢谢你。

© www.soinside.com 2019 - 2024. All rights reserved.