2

How does one create multiple tables using a for loop in postgresql?

For example : I need to create c_emloyee, r_employee, i_employee, etc. I got a syntax error near FOR

! /bin/sh

#Invoke postgre
 SQLVARCHAR="varchar"
 SQLINTEGER="integer"
 SQLBIGINT="bigint"
 SQLSMALLINT="smallint"
 SQLTINYINT="smallint"
 SQLCIDR="cidr"
 SQLBINARY="varbinary"
 SQLTIME="timestamp"
 SQLMACADDRESS="macaddr"
 prefix[0]=c_
 prefix[1]=r_
 prefix[2]=s_
 prefix[3]=i_
 echo ${prefix[0]}
 echo ${prefix[1]}
 echo ${prefix[2]}
 echo ${prefix[3]}

 psql -d postgres <<EOF
 BEGIN 
 FOR i IN 0 1 2 3 LOOP 
 create table ${prefix[i]}employee (e_name $SQLVARCHAR(32) primary key, type $SQLTINYINT not null, description $SQLVARCHAR(128), ip_address $SQLCIDR);
 END LOOP;
 END;
1
  • Please always include the PostgreSQL version and any error messages. Commented Dec 12, 2012 at 23:40

1 Answer 1

2

You're making two mistakes:

  • FOR, BEGIN ... END, etc are part of PL/PgSQL, not regular SQL. You can't use these in plain SQL, you need a DO block or CREATE OR REPLACE FUNCTION.

  • You're seriously muddled about the order of evaluation. You've written a PL/PgSQL FOR loop over i, then you reference i in a bash variable expansion. That'll be expanded during the generation of the PL/PgSQL function text, way before the variable i ever exists.

You can see the latter problem clearly if you just replace psql -d postgres with cat so it prints the generated SQL you're trying to run:

 BEGIN
 FOR i IN 0 1 2 3 LOOP
 create table c_employee (e_name varchar(32) primary key, type smallint not null, description varchar(128), ip_address cidr);
 END LOOP;
 END;

As you can see, ${prefix[i]} evaluated to c_ because i, being undefined, was treated as zero by bash. So the other entries in your prefix array will never be used.

You need to:

  • Use DO block or CREATE OR REPLACE FUNCTION and a function call to execute your PL/PgSQL code; and

  • Use EXECUTE format(...) to run dynamic SQL

Alternately, you can generate the plain SQL CREATE TABLE statements in a bash for loop, doing away entirely with the need for PL/PgSQL. I would use this approach, as it's much simpler.

for p in ${prefix[*]}; do
  echo "create table ${p}employee (e_name $SQLVARCHAR(32) primary key, type $SQLTINYINT not null, description $SQLVARCHAR(128), ip_address $SQLCIDR);"
done | psql

By the way, there is no such thing as postgre. I think you meant "Postgres" or "PostgreSQL".

You probably want bytea not varbinary. What's with the SQL types as variables, anyway? Are you trying to write a DDL generation system? If so, don't reinvent that wheel, there are lots of them already out there.

Also, if you're doing things like this, there's a fairly strong chance you need to read up on schemas (if you're trying to do multi-tenant), table partitioning, etc.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.