How to generate the “create table” sql statement for an existing table in postgreSQL

后端 未结 19 2006
花落未央
花落未央 2020-11-28 17:49

I have created a table in postgreSQL. I want to look at the SQL statement used to create the table but cannot figure it out.

How do I get the create table

相关标签:
19条回答
  • 2020-11-28 18:18

    A simple solution, in pure single SQL. You get the idea, you may extend it to more attributes you like to show.

    with c as (
    SELECT table_name, ordinal_position, 
     column_name|| ' ' || data_type col
    , row_number() over (partition by table_name order by ordinal_position asc) rn
    , count(*) over (partition by table_name) cnt
    FROM information_schema.columns
    WHERE table_name   in ('pg_index', 'pg_tables')
    order by table_name, ordinal_position
    )
    select case when rn = 1 then 'create table ' || table_name || '(' else '' end
     || col 
     || case when rn < cnt then ',' else '); ' end
    from c 
    order by table_name, rn asc;
    

    Output:

    create table pg_index(indexrelid oid,
     indrelid oid,
     indnatts smallint,
     indisunique boolean,
     indisprimary boolean,
     indisexclusion boolean,
     indimmediate boolean,
     indisclustered boolean,
     indisvalid boolean,
     indcheckxmin boolean,
     indisready boolean,
     indislive boolean,
     indisreplident boolean,
     indkey ARRAY,
     indcollation ARRAY,
     indclass ARRAY,
     indoption ARRAY,
     indexprs pg_node_tree,
     indpred pg_node_tree);
    
     create table pg_tables(schemaname name,
     tablename name,
     tableowner name,
     tablespace name,
     hasindexes boolean,
     hasrules boolean,
     hastriggers boolean,
     rowsecurity boolean);
    
    0 讨论(0)
  • 2020-11-28 18:18

    Here is another solution to the old question. There have been many excellent answers to this question over the years and my attempt borrows heavily from them.

    I used Andrey Lebedenko's solution as a starting point because its output was already very close to my requirements.

    Features:

    • following common practice I have moved the foreign key constraints outside the table definition. They are now included as ALTER TABLE statements at the bottom. The reason is that a foreign key can also link to a column of the same table. In that fringe case the constraint can only be created after the table creation is completed. The create table statement would throw an error otherwise.
    • The layout and indenting looks nicer now (at least to my eye)
    • Drop command (commented out) in the header of the definition
    • The solution is offered here as a plpgsql function. The algorithm does however not use any procedural language. The function just wraps one single query that can be used in a pure sql context as well.
    • removed redundant subqueries
    • Identifiers are now quoted if they are identical to reserved postgresql language elements
    • replaced the string concatenation operator || with the appropriate string functions to improve performance, security and readability of the code. Note: the || operator produces NULL if one of the combined strings is NULL. It should only be used when that is the desired behaviour. (check out the usage in the code below for an example)

    CREATE OR REPLACE FUNCTION public.wmv_get_table_definition (
        p_schema_name character varying,
        p_table_name character varying
    )
        RETURNS SETOF TEXT
        AS $BODY$
    BEGIN
        RETURN query 
        WITH table_rec AS (
            SELECT
                c.relname, n.nspname, c.oid
            FROM
                pg_catalog.pg_class c
                LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace
            WHERE
                relkind = 'r'
                AND n.nspname = p_schema_name
                AND c.relname LIKE p_table_name
            ORDER BY
                c.relname
        ),
        col_rec AS (
            SELECT
                a.attname AS colname,
                pg_catalog.format_type(a.atttypid, a.atttypmod) AS coltype,
                a.attrelid AS oid,
                ' DEFAULT ' || (
                    SELECT
                        pg_catalog.pg_get_expr(d.adbin, d.adrelid)
                    FROM
                        pg_catalog.pg_attrdef d
                    WHERE
                        d.adrelid = a.attrelid
                        AND d.adnum = a.attnum
                        AND a.atthasdef) AS column_default_value,
                CASE WHEN a.attnotnull = TRUE THEN
                    'NOT NULL'
                ELSE
                    'NULL'
                END AS column_not_null,
                a.attnum AS attnum
            FROM
                pg_catalog.pg_attribute a
            WHERE
                a.attnum > 0
                AND NOT a.attisdropped
            ORDER BY
                a.attnum
        ),
        con_rec AS (
            SELECT
                conrelid::regclass::text AS relname,
                n.nspname,
                conname,
                pg_get_constraintdef(c.oid) AS condef,
                contype,
                conrelid AS oid
            FROM
                pg_constraint c
                JOIN pg_namespace n ON n.oid = c.connamespace
        ),
        glue AS (
            SELECT
                format( E'-- %1$I.%2$I definition\n\n-- Drop table\n\n-- DROP TABLE IF EXISTS %1$I.%2$I\n\nCREATE TABLE %1$I.%2$I (\n', table_rec.nspname, table_rec.relname) AS top,
                format( E'\n);\n\n\n-- adempiere.wmv_ghgaudit foreign keys\n\n', table_rec.nspname, table_rec.relname) AS bottom,
                oid
            FROM
                table_rec
        ),
        cols AS (
            SELECT
                string_agg(format('    %I %s%s %s', colname, coltype, column_default_value, column_not_null), E',\n') AS lines,
                oid
            FROM
                col_rec
            GROUP BY
                oid
        ),
        constrnt AS (
            SELECT
                string_agg(format('    CONSTRAINT %s %s', con_rec.conname, con_rec.condef), E',\n') AS lines,
                oid
            FROM
                con_rec
            WHERE
                contype <> 'f'
            GROUP BY
                oid
        ),
        frnkey AS (
            SELECT
                string_agg(format('ALTER TABLE %I.%I ADD CONSTRAINT %s %s', nspname, relname, conname, condef), E';\n') AS lines,
                oid
            FROM
                con_rec
            WHERE
                contype = 'f'
            GROUP BY
                oid
        )
        SELECT
            concat(glue.top, cols.lines, E',\n', constrnt.lines, glue.bottom, frnkey.lines, ';')
        FROM
            glue
            JOIN cols ON cols.oid = glue.oid
            JOIN constrnt ON constrnt.oid = glue.oid
            JOIN frnkey ON frnkey.oid = glue.oid;
    END;
    $BODY$
    LANGUAGE plpgsql;
    
    0 讨论(0)
  • 2020-11-28 18:19

    Dean Toader Just excellent! I'd modify your code a little, to show all constraints in the table and to make possible to use regexp mask in table name.

    CREATE OR REPLACE FUNCTION public.generate_create_table_statement(p_table_name character varying)
      RETURNS SETOF text AS
    $BODY$
    DECLARE
        v_table_ddl   text;
        column_record record;
        table_rec record;
        constraint_rec record;
        firstrec boolean;
    BEGIN
        FOR table_rec IN
            SELECT c.relname FROM pg_catalog.pg_class c
                LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace
                    WHERE relkind = 'r'
                    AND relname~ ('^('||p_table_name||')$')
                    AND n.nspname <> 'pg_catalog'
                    AND n.nspname <> 'information_schema'
                    AND n.nspname !~ '^pg_toast'
                    AND pg_catalog.pg_table_is_visible(c.oid)
              ORDER BY c.relname
        LOOP
    
            FOR column_record IN 
                SELECT 
                    b.nspname as schema_name,
                    b.relname as table_name,
                    a.attname as column_name,
                    pg_catalog.format_type(a.atttypid, a.atttypmod) as column_type,
                    CASE WHEN 
                        (SELECT substring(pg_catalog.pg_get_expr(d.adbin, d.adrelid) for 128)
                         FROM pg_catalog.pg_attrdef d
                         WHERE d.adrelid = a.attrelid AND d.adnum = a.attnum AND a.atthasdef) IS NOT NULL THEN
                        'DEFAULT '|| (SELECT substring(pg_catalog.pg_get_expr(d.adbin, d.adrelid) for 128)
                                      FROM pg_catalog.pg_attrdef d
                                      WHERE d.adrelid = a.attrelid AND d.adnum = a.attnum AND a.atthasdef)
                    ELSE
                        ''
                    END as column_default_value,
                    CASE WHEN a.attnotnull = true THEN 
                        'NOT NULL'
                    ELSE
                        'NULL'
                    END as column_not_null,
                    a.attnum as attnum,
                    e.max_attnum as max_attnum
                FROM 
                    pg_catalog.pg_attribute a
                    INNER JOIN 
                     (SELECT c.oid,
                        n.nspname,
                        c.relname
                      FROM pg_catalog.pg_class c
                           LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace
                      WHERE c.relname = table_rec.relname
                        AND pg_catalog.pg_table_is_visible(c.oid)
                      ORDER BY 2, 3) b
                    ON a.attrelid = b.oid
                    INNER JOIN 
                     (SELECT 
                          a.attrelid,
                          max(a.attnum) as max_attnum
                      FROM pg_catalog.pg_attribute a
                      WHERE a.attnum > 0 
                        AND NOT a.attisdropped
                      GROUP BY a.attrelid) e
                    ON a.attrelid=e.attrelid
                WHERE a.attnum > 0 
                  AND NOT a.attisdropped
                ORDER BY a.attnum
            LOOP
                IF column_record.attnum = 1 THEN
                    v_table_ddl:='CREATE TABLE '||column_record.schema_name||'.'||column_record.table_name||' (';
                ELSE
                    v_table_ddl:=v_table_ddl||',';
                END IF;
    
                IF column_record.attnum <= column_record.max_attnum THEN
                    v_table_ddl:=v_table_ddl||chr(10)||
                             '    '||column_record.column_name||' '||column_record.column_type||' '||column_record.column_default_value||' '||column_record.column_not_null;
                END IF;
            END LOOP;
    
            firstrec := TRUE;
            FOR constraint_rec IN
                SELECT conname, pg_get_constraintdef(c.oid) as constrainddef 
                    FROM pg_constraint c 
                        WHERE conrelid=(
                            SELECT attrelid FROM pg_attribute
                            WHERE attrelid = (
                                SELECT oid FROM pg_class WHERE relname = table_rec.relname
                            ) AND attname='tableoid'
                        )
            LOOP
                v_table_ddl:=v_table_ddl||','||chr(10);
                v_table_ddl:=v_table_ddl||'CONSTRAINT '||constraint_rec.conname;
                v_table_ddl:=v_table_ddl||chr(10)||'    '||constraint_rec.constrainddef;
                firstrec := FALSE;
            END LOOP;
            v_table_ddl:=v_table_ddl||');';
            RETURN NEXT v_table_ddl;
        END LOOP;
    END;
    $BODY$
      LANGUAGE plpgsql VOLATILE
      COST 100;
    ALTER FUNCTION public.generate_create_table_statement(character varying)
      OWNER TO postgres;
    

    Now you can, for example, make the following query

    SELECT * FROM generate_create_table_statement('.*');
    

    which results like this:

    CREATE TABLE public.answer (                                                                        
         id integer DEFAULT nextval('answer_id_seq'::regclass) NOT NULL,                               
         questionid integer  NOT NULL,                                                                  
         title character varying  NOT NULL,                                                             
         defaultvalue character varying  NULL,                                                          
         valuetype integer  NOT NULL,                                                                   
         isdefault boolean  NULL,                                                                       
         minval double precision  NULL,                                                                 
         maxval double precision  NULL,                                                                 
         followminmax integer DEFAULT 0 NOT NULL,                                                       
    CONSTRAINT answer_pkey                                                                              
         PRIMARY KEY (id),                                                                              
    CONSTRAINT answer_questionid_fkey                                                                  
         FOREIGN KEY (questionid) REFERENCES question(id) ON UPDATE RESTRICT ON DELETE RESTRICT,       
    CONSTRAINT answer_valuetype_fkey                                                                   
         FOREIGN KEY (valuetype) REFERENCES answervaluetype(id) ON UPDATE RESTRICT ON DELETE RESTRICT);
    

    for each user table.

    0 讨论(0)
  • 2020-11-28 18:21

    If you want to find the create statement for a table without using pg_dump, This query might work for you (change 'tablename' with whatever your table is called):

    SELECT                                          
      'CREATE TABLE ' || relname || E'\n(\n' ||
      array_to_string(
        array_agg(
          '    ' || column_name || ' ' ||  type || ' '|| not_null
        )
        , E',\n'
      ) || E'\n);\n'
    from
    (
      SELECT 
        c.relname, a.attname AS column_name,
        pg_catalog.format_type(a.atttypid, a.atttypmod) as type,
        case 
          when a.attnotnull
        then 'NOT NULL' 
        else 'NULL' 
        END as not_null 
      FROM pg_class c,
       pg_attribute a,
       pg_type t
       WHERE c.relname = 'tablename'
       AND a.attnum > 0
       AND a.attrelid = c.oid
       AND a.atttypid = t.oid
     ORDER BY a.attnum
    ) as tabledefinition
    group by relname;
    

    when called directly from psql, it is usefult to do:

    \pset linestyle old-ascii
    

    Also, the function generate_create_table_statement in this thread works very well.

    0 讨论(0)
  • 2020-11-28 18:22

    DataGrip has the same functionality as pgAdmin. You can right click on a table and you will see option to auto-generate create table statement.

    0 讨论(0)
  • 2020-11-28 18:23

    Another easy option was to use [HeidiSQL client][1] for PostgreSQL database.

    How to go into the database tab where all the databases and tables are listed.

    Click on any of the table/View which you wanted to see the DDL/create a statement of the particular table.

    Now there this client do the following jobs for you for that table, on the right-hand side windows:

    The first window would be for data of table

    Second for your SQL Host information

    Third for database-level information like which tables and what is the size


    Forth which we are more concern about table/view information tab will have the create table statement readily available for you.


    I can not show you in the snapshot as working with confidential data, Try it with yourself and let me know if any issues you guys found.

    0 讨论(0)
提交回复
热议问题