选择一行并插入不同的ID n次

时间:2014-10-22 20:39:20

标签: sql postgresql sql-insert cross-join generate-series

我想在Postgres中创建一个脚本,它将选择表中的第一行并将该行x次插回到同一个表中。

这就是我所拥有的:

INSERT INTO campaign (select column_name from campaign)
SELECT x.id from generate_series(50, 500) as x(id);

以上显然不起作用。

1 个答案:

答案 0 :(得分:2)

只需获取INSERT statement权限的语法:

INSERT INTO campaign (id, column_name)
SELECT g.g, t.column_name
FROM  (SELECT column_name FROM campaign LIMIT 1) t  -- picking arbitrary row
      ,generate_series(50, 500) g(g);               -- 451 times

CROSS JOINgenerate_series()将每个选定的行相乘。

选择一个任意行,因为问题没有定义" first"。表中没有自然顺序。要选择某一行,请添加ORDER BY和/或WHERE

除了名为" id" 的列之外,没有语法快捷方式可以选择 所有列。您必须使用完整行或提供所选列的列表。

动态SQL自动化

要解决此问题,请从目录表(或信息模式)构建查询字符串,并在plpgsql函数(或其他一些过程语言)中使用EXECUTE。仅使用pg_attribute
format()要求Postgres 9.1或更高版本

CREATE OR REPLACE FUNCTION f_multiply_row(_tbl regclass
                                        , _idname text
                                        , _minid int
                                        , _maxid int)
  RETURNS void AS
$func$
BEGIN

   EXECUTE (
      SELECT format('INSERT INTO %1$s (%2$I, %3$s)
                     SELECT g.g, %3$s
                     FROM  (SELECT * FROM %1$s LIMIT 1) t
                           ,generate_series($1, $2) g(g)'
                   , _tbl
                   , _idname
                   , string_agg(quote_ident(attname), ', ')
                   )
      FROM   pg_attribute 
      WHERE  attrelid = _tbl
      AND    attname <> _idname  -- exclude id column
      AND    NOT attisdropped    -- no dropped (dead) columns
      AND    attnum > 0          -- no system columns
      )
   USING _minid, _maxid;

END
$func$ LANGUAGE plpgsql;

打电话给你:

SELECT f_multiply_row('campaign', 'id', 50, 500);

SQL Fiddle.

重点

  • 正确转义标识符以避免SQL注入。使用format()regclass作为表名。详细说明:

  • _idname是要排除的列名称(在您的情况下为&#39; id&#39;)。区分大小写!

  • USING子句中传递$1中的$2generate_series($1, $2)引用了这些参数(不是函数参数)。

相关答案的更多解释。尝试搜索:
https://stackoverflow.com/search?q=[plpgsql]+[dynamic-sql]+format+pg_attribute