How to create multiple tables using for loop in po

2019-05-23 07:53发布

问题:

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:

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.



标签: shell psql