0

I am trying to come up with a script in Postgres that will select the first row in a table and insert that row x number of times back into the same table.

Here is what I have:

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

The above obviously doesn't work.

Erwin Brandstetter
  • 605,456
  • 145
  • 1,078
  • 1,228
dennismonsewicz
  • 25,132
  • 33
  • 116
  • 189

1 Answers1

3

Just get the syntax for the INSERT statement right:

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

The CROSS JOIN to generate_series() multiplies each selected row.

Selecting one arbitrary row, since the question didn't define "first". There is no natural order in a table. To pick a certain row, add ORDER BY and/or WHERE.

There is no syntactical shortcut to select all columns except the one named "id". You have to use the complete row or provide a list of selected columns.

Automation with dynamic SQL

To get around this, build the query string from catalog tables (or the information schema) and use EXECUTE in a plpgsql function (or some other procedural language). Only using pg_attribute.
format() requires Postgres 9.1 or later.

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;

Call in your case:

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

SQL Fiddle.

Major points

  • Properly escape identifiers to avoid SQL injection. Using format() and regclass for the table name. Details:

  • _idname is the column name to exclude ('id' in your case). Case sensitive!

  • Pass values in the USING clause. $1 and $2 in generate_series($1, $2) reference those parameters (not the function parameters).

More explanation in related answers. Try a search:
https://stackoverflow.com/search?q=[plpgsql]+[dynamic-sql]+format+pg_attribute

Community
  • 1
  • 1
Erwin Brandstetter
  • 605,456
  • 145
  • 1,078
  • 1,228
  • I am getting the error of `Error : ERROR: function format(unknown, regclass, text, text) does not exist` – dennismonsewicz Oct 23 '14 at 01:48
  • @dennismonsewicz: I added a fiddle to demonstrate it works in pg 9.3. Also tested with pg 9.2, same result: http://sqlfiddle.com/#!12/b402f/1 – Erwin Brandstetter Oct 23 '14 at 02:04
  • This is how I am using the function... https://gist.github.com/dennismonsewicz/ebba6d714b551b803a28 – dennismonsewicz Oct 23 '14 at 02:17
  • @dennismonsewicz: That's odd. Your code and call look just fine. Seems like [`format()`](http://www.postgresql.org/docs/9.2/interactive/functions-string.html) isn't installed in your system. Are you sure you are running pg 9.2? What do you get with `SELECT version()`? – Erwin Brandstetter Oct 23 '14 at 03:02
  • this is what I get: `psql (9.2.8, server 9.0.18) WARNING: psql version 9.2, server version 9.0. Some psql features might not work.` – dennismonsewicz Oct 23 '14 at 12:48
  • @dennismonsewicz: `psql` is just the default command line interface. You are running Postgres 9.0. `format()` was introduced with 9.1. Consider upgrading to a more current version. Or do the string concatenation without `format()` ... – Erwin Brandstetter Oct 23 '14 at 13:01
  • Then you may be connecting to the wrong database cluster. Get your installation sorted out before you do *anything* else. Remember, [`psql`](http://stackoverflow.com/tags/psql/info) is just the command line interface. You want a new version of Postgres. – Erwin Brandstetter Oct 23 '14 at 13:04
  • How would that function look without using the `format` method? – dennismonsewicz Oct 23 '14 at 13:45
  • @dennismonsewicz: I am not very fond of questions not providing the version information up front. And back-patching to outdated versions is of limited use to the general public. I'll leave that to you. It's not that complicated, though. Start by reading [the manual about `format()`](http://www.postgresql.org/docs/current/interactive/functions-string.html#FUNCTIONS-STRING-FORMAT) to understand what it does. – Erwin Brandstetter Oct 23 '14 at 14:19
  • Fair enough... Thanks! – dennismonsewicz Oct 23 '14 at 15:07