SELECT
column_name,
data_type
FROM
information_schema.columns
WHERE
table_name = 'table_name';
with the above query you can retrieve columns and its datatype.
Answer from selva on Stack OverflowSELECT
column_name,
data_type
FROM
information_schema.columns
WHERE
table_name = 'table_name';
with the above query you can retrieve columns and its datatype.
Open psql command line and type :
\d+ table_name
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.
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.
Does Coefficient work with both Google Sheets and Excel?
Can I export data back to my business systems with Coefficient?
How does Coefficient's automated refresh work?
I don't know why you would ever need to do this, but it is possible using some of the JSON functions introduced in 9.3.
SELECT json_object_keys(row_to_json(t)) FROM
(SELECT * FROM table1
LEFT JOIN table2 ON table1.id = table2.tbl1_id LIMIT 1) t;
This will give you the name of every column returned for a single row. Without the LIMIT you would get the columns repeated for every row returned. If you wanted to see the values returned as well you can get more complex:
WITH t as
(SELECT * FROM table1
LEFT JOIN table2 ON table1.id = table2.tbl1_id LIMIT 1)
SELECT json_data.key, json_data.value
FROM t, json_each_text(row_to_json(t)) AS json_data;
Both these queries will return all the columns even if they are named the same. If all you want is a list of unique column names, you can utilize hstore:
CREATE EXTENSION hstore; --Create the extension if you need it.
SELECT akeys(hstore(t)) as array_of_columns
FROM
(SELECT * FROM table1
LEFT JOIN table2 ON table1.id = table2.tbl1id LIMIT 1) t;
The only reasonable approach I can come up with is to do something like this. Schema location plays into this, but I'm just posting the basic idea. SQL doesn't have reflection at run time unless you go and hit meta data tables, which is what you seem to be trying to achieve here.
SELECT table1.*
INTO x
FROM table1
LEFT JOIN table2
ON table1.id = table2.tbl1_id LIMIT 0;
select *
from information_schema.columns
where table_Name = 'x';
Also interesting enough while traveling the Internets over lunch I ran into this. Works with PostgreSQL 8.2.0 or higher.
https://github.com/theory/colnames/tree/master/test/sql
With Postgres (and its JDBC driver) you can do the following:
PreparedStatement pstmt = con.prepareStatement("select ... ");
ResultSetMetaData meta = pstmt.getMetaData();
for (int i=1; i <= meta.getColumnCount(); i++)
{
System.out.println("Column name: " + meta.getColumnName(i) + ", data type: " + meta.getColumnTypeName(i));
}
Note that you do not need to add a where false or limit 0 to the statement. The call to prepareStatement() does not actually execute the query.
Given an SQL statement as a string, could you not add " LIMIT=0" to the string and run the modified query? Of course this would only get the column names, but these could then be used to query the information schema for the types.
If the SQL already contains a limit, its argument could be modified?
Information schema vs. system catalogs
The information schema serves certain purposes. System catalogs are the actual source of truth in Postgres.
The information schema provides standardized views which help with portability - mostly across major Postgres versions as portability across different RDBMS platforms typically is an illusion once your queries are sophisticated enough to look up system catalogs. Notably, major RDBMS like Oracle, SQLite, IBM Db2, SAP ASE, or IBM Informix still don't support the information schema (as of June 2026).
Views in the information schema must jump through many hoops to achieve a format complying to the standard. This makes them slow, sometimes very slow. Compare plans and performance for these basic objects:
EXPLAIN ANALYZE SELECT * from information_schema.columns;
EXPLAIN ANALYZE SELECT * from pg_catalog.pg_attribute;
The difference is remarkable.
Your example
For your example SELECT * from tbl compare the two queries below for this simple table:
CREATE TEMP TABLE foo(
a numeric(12,3)
, b timestamp(0)
);
Using pg_attribute:
SELECT attname, format_type(atttypid, atttypmod) AS type
FROM pg_attribute
WHERE attrelid = 'foo'::regclass
AND attnum > 0
AND NOT attisdropped
ORDER BY attnum;
format_type() returns the complete type with all modifiers:
attname | type
--------+-------------------------------
a | numeric(12,3)
b | timestamp(0) without time zone
Also note that the cast to regclass resolves the table name according to the current search_path. It raises an exception if the name is not valid. See:
- ERROR: could not find array type for datatype information_schema.sql_identifier
Using information_schema.columns:
SELECT column_name, data_type
FROM information_schema.columns
WHERE table_name = 'foo'
ORDER BY ordinal_position;
The information is standardized, but incomplete:
column_name | data_type
------------+----------------------------
a | numeric
b | timestamp without time zone
To get full information for the data type you need to consider all of these columns additionally:
character_maximum_length
character_octet_length
numeric_precision
numeric_precision_radix
numeric_scale
datetime_precision
interval_type
interval_precision
Related answers:
- How to check if a table exists in a given schema
- List all columns for a specified table
List of pros & cons
The biggest pros (IMO) in bold.
Information schema views
- often simpler (depends)
- slow
- preprocessed, which may or may not suit your needs
- selective (users only see objects they have privileges for)
- conforming to an SQL standard (that's implemented by some of the major RDBMS)
- mostly portable across major Postgres versions
- do not require much specific knowledge about Postgres
- identifiers are descriptive, long and sometimes awkward
System catalogs
- often more complex (depends), closer to the source
- fast
- complete (system columns like
oidincluded) - not complying to an SQL standard
- less portable across major Postgres versions (but basics aren't going to change)
- require more specific knowledge about Postgres
- identifiers are terse, less descriptive but conveniently short
Arbitrary query
To get the same list of column names and types from a query, you could use a simple trick: CREATE a temporary table from the query output, then use the same techniques as above.
You can append LIMIT 0, since you do not need actual data:
CREATE TEMP TABLE tmp123 AS
SELECT 1::numeric, now()
LIMIT 0;
To get the data type of individual columns, you can also use the function pg_typeof():
SELECT pg_typeof(1);
You can use the psql command line client.
\dt will show a list of tables
\dv will show a list of views
\d [object_name] will describe the schema of the table or view
Not sure how you would describe a query though.
More info: https://manikandanmv.wordpress.com/tag/basic-psql-commands/