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

后端 未结 19 2004
花落未央
花落未央 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:06

    My solution is to log in to the postgres db using psql with the -E option as follows:

    psql -E -U username -d database   
    

    In psql, run the following commands to see the sql that postgres uses to generate
    the describe table statement:

    -- List all tables in the schema (my example schema name is public)
    \dt public.*
    -- Choose a table name from above
    -- For create table of one public.tablename
    \d+ public.tablename  
    

    Based on the sql echoed out after running these describe commands, I was able to put together
    the following plpgsql function:

    CREATE OR REPLACE FUNCTION generate_create_table_statement(p_table_name varchar)
      RETURNS text AS
    $BODY$
    DECLARE
        v_table_ddl   text;
        column_record record;
    BEGIN
        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 ~ ('^('||p_table_name||')$')
                    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;
    
        v_table_ddl:=v_table_ddl||');';
        RETURN v_table_ddl;
    END;
    $BODY$
      LANGUAGE 'plpgsql' COST 100.0 SECURITY INVOKER;
    

    Here is the function usage:

    SELECT generate_create_table_statement('tablename');
    

    And here is the drop statement if you don't want this function to persist permanently:

    DROP FUNCTION generate_create_table_statement(p_table_name varchar);
    
    0 讨论(0)
  • 2020-11-28 18:07

    Here is a single statement that will generate the DDL for a single table in a specified schema, including constraints.

    SELECT 'CREATE TABLE ' || pn.nspname || '.' || pc.relname || E'(\n' ||
       string_agg(pa.attname || ' ' || pg_catalog.format_type(pa.atttypid, pa.atttypmod) || coalesce(' DEFAULT ' || (
                                                                                                                   SELECT pg_catalog.pg_get_expr(d.adbin, d.adrelid)
                                                                                                                   FROM pg_catalog.pg_attrdef d
                                                                                                                   WHERE d.adrelid = pa.attrelid
                                                                                                                     AND d.adnum = pa.attnum
                                                                                                                     AND pa.atthasdef
                                                                                                                   ),
                                                                                                     '') || ' ' ||
                  CASE pa.attnotnull
                      WHEN TRUE THEN 'NOT NULL'
                      ELSE 'NULL'
                  END, E',\n') ||
       coalesce((SELECT E',\n' || string_agg('CONSTRAINT ' || pc1.conname || ' ' || pg_get_constraintdef(pc1.oid), E',\n' ORDER BY pc1.conindid)
                FROM pg_constraint pc1
                WHERE pc1.conrelid = pa.attrelid), '') ||
       E');'
    FROM pg_catalog.pg_attribute pa
    JOIN pg_catalog.pg_class pc
        ON pc.oid = pa.attrelid
        AND pc.relname = 'table_name'
    JOIN pg_catalog.pg_namespace pn
        ON pn.oid = pc.relnamespace
        AND pn.nspname = 'schema_name'
    WHERE pa.attnum > 0
        AND NOT pa.attisdropped
    GROUP BY pn.nspname, pc.relname, pa.attrelid;
    
    0 讨论(0)
  • 2020-11-28 18:08

    This is the variation that works for me:

    pg_dump -U user_viktor -h localhost unit_test_database -t floorplanpreferences_table --schema-only

    In addition, if you're using schemas, you'll of course need to specify that as well:

    pg_dump -U user_viktor -h localhost unit_test_database -t "949766e0-e81e-11e3-b325-1cc1de32fcb6".floorplanpreferences_table --schema-only

    You will get an output that you can use to create the table again, just run that output in psql.

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

    Like the other answers mentioned, there is no built in function that does this.

    Here is a function that attempts to get all of the information that would be needed to replicate the table - or to compare deployed and checked in ddl.

    This function outputs:

    • columns (w/ precision, null/not-null, default value)
    • constraints
    • indexes
    
    CREATE OR REPLACE FUNCTION public.show_create_table(
      in_schema_name varchar,
      in_table_name varchar
    )
    RETURNS text
    LANGUAGE plpgsql VOLATILE
    AS
    $$
      DECLARE
        -- the ddl we're building
        v_table_ddl text;
    
        -- data about the target table
        v_table_oid int;
    
        -- records for looping
        v_column_record record;
        v_constraint_record record;
        v_index_record record;
      BEGIN
        -- grab the oid of the table; https://www.postgresql.org/docs/8.3/catalog-pg-class.html
        SELECT c.oid INTO v_table_oid
        FROM pg_catalog.pg_class c
        LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace
        WHERE 1=1
          AND c.relkind = 'r' -- r = ordinary table; https://www.postgresql.org/docs/9.3/catalog-pg-class.html
          AND c.relname = in_table_name -- the table name
          AND n.nspname = in_schema_name; -- the schema
    
        -- throw an error if table was not found
        IF (v_table_oid IS NULL) THEN
          RAISE EXCEPTION 'table does not exist';
        END IF;
    
        -- start the create definition
        v_table_ddl := 'CREATE TABLE ' || in_schema_name || '.' || in_table_name || ' (' || E'\n';
    
        -- define all of the columns in the table; https://stackoverflow.com/a/8153081/3068233
        FOR v_column_record IN
          SELECT
            c.column_name,
            c.data_type,
            c.character_maximum_length,
            c.is_nullable,
            c.column_default
          FROM information_schema.columns c
          WHERE (table_schema, table_name) = (in_schema_name, in_table_name)
          ORDER BY ordinal_position
        LOOP
          v_table_ddl := v_table_ddl || '  ' -- note: two char spacer to start, to indent the column
            || v_column_record.column_name || ' '
            || v_column_record.data_type || CASE WHEN v_column_record.character_maximum_length IS NOT NULL THEN ('(' || v_column_record.character_maximum_length || ')') ELSE '' END || ' '
            || CASE WHEN v_column_record.is_nullable = 'NO' THEN 'NOT NULL' ELSE 'NULL' END
            || CASE WHEN v_column_record.column_default IS NOT null THEN (' DEFAULT ' || v_column_record.column_default) ELSE '' END
            || ',' || E'\n';
        END LOOP;
    
        -- define all the constraints in the; https://www.postgresql.org/docs/9.1/catalog-pg-constraint.html && https://dba.stackexchange.com/a/214877/75296
        FOR v_constraint_record IN
          SELECT
            con.conname as constraint_name,
            con.contype as constraint_type,
            CASE
              WHEN con.contype = 'p' THEN 1 -- primary key constraint
              WHEN con.contype = 'u' THEN 2 -- unique constraint
              WHEN con.contype = 'f' THEN 3 -- foreign key constraint
              WHEN con.contype = 'c' THEN 4
              ELSE 5
            END as type_rank,
            pg_get_constraintdef(con.oid) as constraint_definition
          FROM pg_catalog.pg_constraint con
          JOIN pg_catalog.pg_class rel ON rel.oid = con.conrelid
          JOIN pg_catalog.pg_namespace nsp ON nsp.oid = connamespace
          WHERE nsp.nspname = in_schema_name
          AND rel.relname = in_table_name
          ORDER BY type_rank
        LOOP
          v_table_ddl := v_table_ddl || '  ' -- note: two char spacer to start, to indent the column
            || 'CONSTRAINT' || ' '
            || v_constraint_record.constraint_name || ' '
            || v_constraint_record.constraint_definition
            || ',' || E'\n';
        END LOOP;
    
        -- drop the last comma before ending the create statement
        v_table_ddl = substr(v_table_ddl, 0, length(v_table_ddl) - 1) || E'\n';
    
        -- end the create definition
        v_table_ddl := v_table_ddl || ');' || E'\n';
    
        -- suffix create statement with all of the indexes on the table
        FOR v_index_record IN
          SELECT indexdef
          FROM pg_indexes
          WHERE (schemaname, tablename) = (in_schema_name, in_table_name)
        LOOP
          v_table_ddl := v_table_ddl
            || v_index_record.indexdef
            || ';' || E'\n';
        END LOOP;
    
        -- return the ddl
        RETURN v_table_ddl;
      END;
    $$;
    

    example

    SELECT * FROM public.show_create_table('public', 'example_table');
    

    produces

    CREATE TABLE public.example_table (
      id bigint NOT NULL DEFAULT nextval('test_tb_for_show_create_on_id_seq'::regclass),
      name character varying(150) NULL,
      level character varying(50) NULL,
      description text NOT NULL DEFAULT 'hello there!'::text,
      CONSTRAINT test_tb_for_show_create_on_pkey PRIMARY KEY (id),
      CONSTRAINT test_tb_for_show_create_on_level_check CHECK (((level)::text = ANY ((ARRAY['info'::character varying, 'warn'::character varying, 'error'::character varying])::text[])))
    );
    CREATE UNIQUE INDEX test_tb_for_show_create_on_pkey ON public.test_tb_for_show_create_on USING btree (id);
    
    0 讨论(0)
  • 2020-11-28 18:13

    If you want to do this for various tables at once, you meed to use the -t switch multiple times (took me a while to figure out why comma separated list wasn't working). Also, can be useful to send results to an outfile or pipe to a postgres server on another machine

    pg_dump -t table1 -t table2 database_name --schema-only > dump.sql
    
    pg_dump -t table1 -t table2 database_name --schema-only | psql -h server_name database_name
    
    0 讨论(0)
  • 2020-11-28 18:13

    In pgadminIII database>>schemas>>tables>> right click on 'Your table'>>scripts>> 'Select any one (Create,Insert,Update,Delete..)'

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