Query the schema details of a table in PostgreSQL? - postgresql

I need to know the column type in PostgreSQL (i.e. varchar(20)). I know that I could probably find this using \d something in psql, but I need it to be done with a select query.
Is this possible in PostgreSQL?

There is a much simpler way in PostgreSQL to get the type of a column.
SELECT pg_typeof(col)::text FROM tbl LIMIT 1
The table must hold at least one row, of course. And you only get the base type without type modifiers (if any). Use the alternative below if you need that, too.
You can use the function for constants as well. The manual on pg_typeof().
For an empty (or any) table you can use query the system catalog pg_attribute to get the full list of columns and their respective type in order:
SELECT attnum, attname AS column, format_type(atttypid, atttypmod) AS type
FROM pg_attribute
WHERE attrelid = 'myschema.mytbl'::regclass -- optionally schema-qualified
AND NOT attisdropped
AND attnum > 0
ORDER BY attnum;
The manual on format_type() and on object identifier types like regclass.

You can fully describe a table using postgres with the following query:
SELECT
a.attname as Column,
pg_catalog.format_type(a.atttypid, a.atttypmod) as Datatype
FROM
pg_catalog.pg_attribute a
WHERE
a.attnum > 0
AND NOT a.attisdropped
AND a.attrelid = (
SELECT c.oid
FROM pg_catalog.pg_class c
LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace
WHERE c.relname ~ '^(TABLENAME)$'
AND pg_catalog.pg_table_is_visible(c.oid)
)
Tith this you will retrieve column names and data type.
It is also possible to start psql client using the -E option
$ psql -E
And then a simple \d mytable will output the queries used by postgres to describe the table. It work for every psql describe commands.

Yes, look at the information_schema.

Related

PostgreSQL n_distinct statistics setting

Are there multiple ways to set n_distinct in PostgreSQL? Both of these seem to be doing the same thing but end up changing a different value within pg_attribute. What is the difference between these two commands?
alter table my_table alter column my_column set (n_distinct = 500);
alter table my_table alter column my_column set statistics 1000;
select
c.relname,
a.attname,
a.attoptions,
a.attstattarget
from
pg_class c
inner join
pg_attribute a
on c.oid = a.attrelid
where
c.relname = 'my_table'
and
a.attname = 'my_column'
order by
c.relname,
a.attname;
Name |Value
-------------|----------------
relname |my_table
attname |my_column
attoptions |{n_distinct=500}
attstattarget|1000
Both of these seem to be doing the same thing
Why would you say that? Both commands are obviously distinct. Both are related to column statistics and query planning. But they do very different things.
The statistics target ...
controls the level of detail of statistics accumulated for this column by ANALYZE. See:
Check statistics targets in PostgreSQL
Basics in the manual.
Setting n_distinct is something completely different. It means hard-coding the number (or ratio) of distinct values to expect for the given column. (But only effective after the next ANALYZE.)
Related answer on dba.SE with more on n_distinct:
Very bad query plan in PostgreSQL 9.6

PostgreSQL 12 - List sequences that do not match their related table name

I have a database with plenty of tables.
I want to tidy up relations that do not fit namewise anymore, due to name changes of the tables.
I was able to fix the constraints, but I am not able to put the lines together to list the sequences and the related columns. As pgAdmin shows under dependencies the column a sequence is connected to, it should be possible to create a SELECT to show sequences and their related column.
Try this:
SELECT a.attrelid::regclass AS table_name,
a.attname AS column_name,
pg_get_serial_sequence(a.attrelid::regclass::text, a.attname) AS sequence_name
FROM pg_attribute AS a
JOIN pg_class AS t ON a.attrelid = t.oid
WHERE t.relkind IN ('r', 'P')
AND NOT a.attisdropped
AND pg_get_serial_sequence(a.attrelid::regclass::text, a.attname) IS NOT NULL;

How to introspect materialized views

I have a utility that introspects columns of tables using:
select column_name, data_type from information_schema.columns
where table_name=%s
How can I extend this to introspect columns of materialized views?
Your query carries a few shortcomings / room for improvement:
A table name is not unique inside a database, you would have to narrow down to a specific schema, or could get surprising / misleading / totally incorrect results.
It's much more effective / convenient to cast the (optionally) schema-qualified table name to regclass ... see below.
A cast to regtype gives you generic type names instead of internal ones. But that's still only the base type.
Use the system catalog information functions format_type() instead to get an exact type name including modifiers.
With the above improvements you don't need to join to additional tables. Just pg_attribute.
Dropped columns reside in the catalog until the table is vacuumed (fully). You need to exclude those.
SELECT attname, atttypid::regtype AS base_type
, format_type(atttypid, atttypmod) AS full_type
FROM pg_attribute
WHERE attrelid = 'myschema.mytable'::regclass
AND attnum > 0
AND NOT attisdropped; -- no dead columns
As an aside: the views in the information schema are only good for standard compliance and portability (rarely works anyway). If you don't plan to switch your RDBMS, stick with the catalog tables, which are much faster - and more complete, apparently.
It would seem that postgres 9.3 has left materialized views out of the information_schema. (See http://postgresql.1045698.n5.nabble.com/Re-Materialized-views-WIP-patch-td5740513i40.html for a discussion.)
The following will work for introspection:
select attname, typname
from pg_attribute a
join pg_class c on a.attrelid = c.oid
join pg_type t on a.atttypid = t.oid
where relname = %s and attnum >= 1;
The clause attnum >= 1 suppresses system columns. The type names are pg_specific this way, I guess, but good enough for my purposes.

POSTGRESQL: DUMP TABLE WITHOUT TOAST DATA

I am trying to isolate toast data from a table so that I can dump the table without the toast data. I know there must be a way to do that, but I cant get my way there...Suggestions would be highly appreciated
Try a COPY (or psql's \copy) with the query option - you can select the columns to export. You can also choose a CSV format rather than tab-separated, the representation of nulls etc.
TOAST is the way how PostgreSQL is storing your data internally. For you, as a user, there is only values that you delegated to the database to keep for you.
TOAST comes into play mostly for the textual data, when any of the tuple's attributes make tuple's size to be more then 8k (if PostgreSQL compiled with default page size). This happens inside the DB engine, transparently to the user. Say, if you'll insert a row with a text that has round 10k symbols, the corresponding attribute will be TOASTed.
Given how TOAST works, your question appears to look like: How do I dump table without attributes containing big chunks of data? It seems unclear for me what would be the purpose of this, as your dump will be incomplete.
EDIT: I don't know how to find if any attribute of any tuple do have a TOASTed value. Instead, I will eliminate all attributes that can have TOASTed values.
The following query will give you all the columns for a table, that are always in PLAIN storage mode:
SELECT a.attname
FROM pg_class t
JOIN pg_attribute a ON t.oid = a.attrelid
JOIN pg_type typ ON typ.oid = a.atttypid
WHERE t.relkind='r' AND t.relname = 'element'
AND a.attnum > 0 AND NOT a.attisdropped
AND typ.typstorage='p'
ORDER BY a.attnum;
And this query will generate the desired SQL, you can wrap it in the script or into the PL/pgSQL's EXECUTE statement:
SELECT 'COPY '||quote_ident(t.relname)||
'('||string_agg(a.attname, ',' ORDER BY a.attnum)||') TO stdout;'
FROM pg_class t
JOIN pg_attribute a ON t.oid = a.attrelid
JOIN pg_type typ ON typ.oid = a.atttypid
WHERE t.relkind='r' AND t.relname = '<YOUR_TABLE>'
AND a.attnum > 0 AND NOT a.attisdropped
AND typ.typstorage='p'
GROUP BY t.relname;

Find out if user got permission to select/update/... a table/function/... in PostgreSQL

What is the recommended way to figure out if a user got a certain right (e.g. select or execute) on a certain class (e.g. table or function) in PostgreSQL?
At the moment I got something like
aclcontains(
someColumnWithAclitemArray,
makeaclitem(userOid,grantorOid,someRight,false))
but it's terrible since I have to check for every grantorOid that is possible and for every userOid the user can belong to.
On a related note: what are the possible rights you can test for?
I haven't found any documentation but reading the source code I guess:
INSERT
SELECT
UPDATE
DELETE
TRUNCATE
REFERENCES
TRIGGER
EXECUTE
USAGE
CREATE
CONNECT
There also seems to be a CREATE TEMP right, but I can't figure out the correct text to use in the makeaclitem-function.
I've found that a better approach (and I seem to remember this was taken from some queries built into psql, or maybe the information_schema views) is to use the has_*_privilege functions, and simply apply them to a set of all possible combinations of user and object. This will take account of having access to an object via some group role as well.
For example, this will show which users have which access to non-catalogue tables and views:
select usename, nspname || '.' || relname as relation,
case relkind when 'r' then 'TABLE' when 'v' then 'VIEW' end as relation_type,
priv
from pg_class join pg_namespace on pg_namespace.oid = pg_class.relnamespace,
pg_user,
(values('SELECT', 1),('INSERT', 2),('UPDATE', 3),('DELETE', 4)) privs(priv, privorder)
where relkind in ('r', 'v')
and has_table_privilege(pg_user.usesysid, pg_class.oid, priv)
and not (nspname ~ '^pg_' or nspname = 'information_schema')
order by 2, 1, 3, privorder;
The possible privileges are detailed in the description of the has_*_privilege functions at http://www.postgresql.org/docs/current/static/functions-info.html#FUNCTIONS-INFO-ACCESS-TABLE.
'CREATE TEMP' is a database-level privilege: it permits a user to use a pg_temp_* schema. It can be tested with has_database_privilege(useroid, datoid, 'TEMP').
Take a look at the "Access Privilege Inquiry Functions" and also the "GRANT" reference page.
Because Redshift is supporting values() only in INSERT INTO queries, the below query can be used with the obviously not-so-nice union all select.
select usename, nspname || '.' || relname as relation,
case relkind when 'r' then 'table' when 'v' then 'view' end as relation_type,
priv
from pg_class join pg_namespace on pg_namespace.oid = pg_class.relnamespace,
pg_user,
(select 'select' as priv,1 as privorder union all select 'insert',2 union all select 'update',3 union all select 'delete',4)
where relkind in ('r', 'v')
and has_table_privilege(pg_user.usesysid, pg_class.oid, priv)
and not (nspname ~ '^pg_' or nspname = 'information_schema')
order by 2, 1, 3, privorder;
Edit:
Also, I realized, that in our db Dataiku creates tables that can have CAPITAL letter in them, so, if table not exist error happens, you should use the lower() function