529

I'm looking for a precise piece of information in a database which I have no knowledge about. The database is on a separate machine, but I can log into it, and launch a psql command line, with administrator rights.

It's a third-party product, and they are slow to answer questions. I know the data is inside that database, so I want to do a little bit of reverse-engineering.

Given a table name, is it possible to get a list of the names of the columns in that table?

For example, in SQL Server, it's possible to dump a table into a reusable CREATE statement, which textually lists all the columns the table is composed of.

0

5 Answers 5

636

In addition to the command line \d+ <table_name> you already found, you could also use the Information Schema to look up the column data, using information_schema.columns:

SELECT *
  FROM information_schema.columns
 WHERE table_schema = 'your_schema'
   AND table_name   = 'your_table'
     ;

Note: As per the example above, make sure the values are enclosed within quotes.

3
  • 11
    add order by ordinal_position to preserve column order Nov 19, 2021 at 12:34
  • 1
    And table name is case sensitive.. lower case was ok. Jan 24, 2022 at 23:41
  • 8
    Just to make make copy paste to psql easier: SELECT column_name FROM information_schema.columns where table_name = 'TABLE_NAME'; Sep 21, 2022 at 11:57
153

As a supplement to the other answers, even a SELECT statement that returns no rows will expose the column names to you and to application code.

select *
from table_name
where false;

I intend this to be executable by almost any client software for almost any DBMS. (Almost? Yes, some don't support a clause like where false. Instead, they require an expression like where 1 = 0.)

Permissions might come into play with any of these approaches.

3
  • 2
    Except for the hidden columns, which had to be specified to be selected (like pg_class.oid)
    – okutane
    Feb 19, 2019 at 15:06
  • Note, for some DBMSes "where (false / or false condition)" clause could be slow as it may scan all table records for condition check, depends on how smart the optimizer is. Alternatively, may consider the rows limit clause.
    – Marcodor
    Jul 12 at 8:09
  • To get one line of data: COPY (SELECT * FROM table_name WHERE false) TO STDOUT WITH (FORMAT CSV, HEADER);
    – meolic
    Aug 21 at 9:37
93

The information schema is the slow and sure way: it is standardized and largely portable to other databases that support it. And it will keep working across major versions.

However, views in the information schema often join many tables from the system catalogs to meet a strictly standardized format - many of which are just dead freight most of the time. This makes them slow.
The Postgres developers aren't making promises, but basics (like what is needed here) aren't going to change across major versions.

More detailed assessment:

psql (the native command-line interface) takes the fast lane, of course, and queries the source directly. If you start psql with the parameter -E, the SQL behind backslash commands like \d is displayed. Or \set ECHO_HIDDEN on from the psql command line. Starting from there you can build an answer to your question.

Given one table, is it possible to have a list of the names of the columns for this table.

SELECT attrelid::regclass AS tbl
     , attname            AS col
     , atttypid::regtype  AS datatype
       -- more attributes?
FROM   pg_attribute
WHERE  attrelid = 'myschema.mytable'::regclass  -- table name optionally schema-qualified
AND    attnum > 0
AND    NOT attisdropped
ORDER  BY attnum;

Faster than querying information_schema.columns. Try EXPLAIN ANALYZE to see for yourself. Still hardly matters for a one-time look-up. But might make a difference if used in a query / function that's repeated many times.

There are also subtle differences in visibility. Detailed comparison:

1
  • thanks for the NOT attisdropped. my query without that was working well until i dropped a column and got unexpected "pg:dropped......" in my output of the function i wrote. Apr 22 at 14:08
14

psql on PostgreSQL 11+

If you're looking for the column types on a query, you can use psql's \gdesc

SELECT
    NULL AS zero,
    1 AS one,
    2.0 AS two,
    'three' AS three,
    $1 AS four,
    sin($2) as five,
    'foo'::varchar(4) as six,
    CURRENT_DATE AS now
\gdesc
 Column |         Type         
--------+----------------------
 zero   | text
 one    | integer
 two    | numeric
 three  | text
 four   | text
 five   | double precision
 six    | character varying(4)
 now    | date
(8 rows)
9

PostgreSQL only

This is somewhat hokey but could be a contender if you are looking for the shortest possible SQL:

SELECT json_object_keys(to_json(json_populate_record(NULL::schema_name.table_name, '{}'::JSON)))

or even shorter (assuming there is at least one row present in the table)

SELECT json_object_keys(to_json((SELECT t FROM schema_name.table_name t LIMIT 1)))

The listing preserves the order. In case you don't care about the order and have hstore extension installed you can do even shorter

SELECT skeys(hstore(NULL::schema_name.table_name))
2
  • This this return the column names in the same order that SELECT * returns the column values? Nov 25, 2021 at 7:32
  • 1
    A magical feature of this approach is that it works for views also.
    – Shane
    Jul 20, 2022 at 0:01

Not the answer you're looking for? Browse other questions tagged or ask your own question.