将行乘以列值

时间:2021-06-22 14:35:30

标签: sql postgresql nested-loops plpgsql

我需要将数据从源表转换为目标表。

源表具有“内容”列和“乘数”列。根据乘数(X),源的内容应该X次写入目标。

例如:如果 multilpier 为 '0',则不会写入任何内容,如果为 '1',则将内容一次写入目标表。两次,如果乘数为“2”,依此类推。我以前从未在 Postgres 中做过函数。

我的方法:嵌套 for-while 循环:对于每一行,当“计数器”小于“乘数”时,将源表中的内容插入到目标表中。

示例数据:

--create source table
create table public.source_tbl(
id serial, 
multiplier int, 
content varchar,
primary key (id)
);
--create destination table
create table public.dest_tbl(
id serial, 
multiplier int, 
content varchar,
primary key (id)
);
--some content
insert into public.source_tbl(multiplier,content)
values(1,'foo'),(1,'bar'),(1,'random'),(2, 'content'),(3,'My'),(4,'creativity'),(3,'is'),(2,'very'),(6,'limited'),(7,'!!!'), (0, 'nothing should be written');

这就是我想出的代码:

do
$$
declare f record;
begin 
    for f in    select id, multiplier, content
                from public.source_tbl;
    loop
        do
        $$
        declare counter integer counter:=0;
        begin
            while counter < f.multiplier
            loop
                insert into public.dest_tbl(multiplier,content)
                select f.multiplier, f.content;
                counter := counter +1;
            end loop;
        end;
    end loop;
end;
$$

不用说它不起作用,我收到第二个“声明”的语法错误。那么我做错了什么?

2 个答案:

答案 0 :(得分:2)

Jim 立即回答了有关语法错误的问题。但是,为此您不需要函数或 PL/pgSQL。同样可以通过使用内置函数 generate_series()

insert into dest_tbl (multiplier, content)
select st.multiplier, st.content
from source_tbl st
  cross join generate_series(1, st.multiplier);

答案 1 :(得分:1)

您不能在 plpgsql 代码中间声明变量。也没有必要为第二个循环创建另一个匿名代码块。试试这个:

do
$$ 
declare 
 f record;
 counter integer :=0;
begin 
    for f in select id, multiplier, content from public.source_tbl  loop
      while counter < f.multiplier loop
         insert into public.dest_tbl(multiplier,content)
         select f.multiplier, f.content;
         counter := counter +1;
       end loop;   
       counter := 0;
    end loop;
end;
$$ language plpgsql;

演示:db<>fiddle