【问题标题】:Select a row and insert it with different IDs n times选择一行并用不同的 ID 将其插入 n 次
【发布时间】:2014-10-22 20:39:19
【问题描述】:

我正在尝试在 Postgres 中编写一个脚本,该脚本将选择表中的第一行并将该行 x 多次插入到同一个表中。

这是我所拥有的:

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

以上显然行不通。

【问题讨论】:

  • 您要动态选择要插入的列吗?
  • 请定义“第一行”。并详细说明要选择/插入哪些列。只是给定的column_name?还是除id 之外的整行?另外,总是你的 Postgres 版本。
  • @ErwinBrandstetter - 不一定是“第一行”,只是表中已经存在的随机行。我想使用随机选择的行中每个列名的所有值。 Postgres 版本是 9.2
  • 对于“每一列”?您的意思是除id 之外的每一列,您想为其提供一个新值,对吧?
  • @ErwinBrandstetter 正确

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


【解决方案1】:

只需获取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() 将每个选定的行相乘。

选择一个 任意 行,因为问题没有定义“第一”。表中没有自然顺序。要选择某一行,请添加 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 是要排除的列名(在您的情况下为“id”)。区分大小写!

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

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

【讨论】:

  • 我收到Error : ERROR: function format(unknown, regclass, text, text) does not exist的错误
  • @dennismonsewicz:我添加了一个小提琴来演示它在 pg 9.3 中的工作原理。还使用 pg 9.2 进行了测试,结果相同:sqlfiddle.com/#!12/b402f/1
  • 这就是我使用函数的方式...gist.github.com/dennismonsewicz/ebba6d714b551b803a28
  • @dennismonsewicz:这很奇怪。您的代码和调用看起来很好。似乎format() 未安装在您的系统中。你确定你正在运行 pg 9.2 吗? SELECT version() 有什么用?
  • 这是我得到的:psql (9.2.8, server 9.0.18) WARNING: psql version 9.2, server version 9.0. Some psql features might not work.
猜你喜欢
  • 2011-07-31
  • 2021-07-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-01-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多