How to get the name of a unique constraint in postgresql? - sql

I need to drop a unique constraint from a postgresql table, but I didn't give it a name in the schema. Does anybody know, how to get the name of such a constraint, or how to drop it?

That is something like (for single column constaint):
tableName_columnName_key
To get constaint name write (in psql):
\d tableName
or use pg_constraint system catalog:
SELECT conname
FROM pg_constraint
WHERE conrelid =
(SELECT oid
FROM pg_class
WHERE relname LIKE 'tableName');
Also you can get it from pgAdmin in objects tree.

SELECT conname
FROM pg_constraint
WHERE conrelid = 'mytable'::regclass::oid

Related

How do I SELECT all (table, column) referencing the same column as foreign key

(TL;DR at the end)
I am working on merging 2 well sized postgres databases.
As there are ID conflicts and many foreign keys I would have enjoyed that UPDATE foo SET bar_id = bar_id + 100000 CASCADE was a thing in SQL so it magically update everything accordingly. Unfortunately, it's not.
So I want to use a LOOP structure (see below) that will simply edit the references everywhere.
I want a select query the return all table_name, column_name that references the column I want.
DO
$$
DECLARE
rec record;
BEGIN
FOR rec IN
(SELECT table_name, column_name FROM /*??*/ WHERE /*??*/) -- <<< This line
LOOP
EXECUTE format('UPDATE %I SET %s = %s + 100000 ;',
rec.table_name,rec.column_name,rec.column_name);
END LOOP;
END;
$$
LANGUAGE plpgsql;
I know already how to get all tables (+column_name) having a specific column_name that I use when the foreign key column share the name with the column it references. Or even if it's a list of column_name I know:
SELECT col.table_name, col.column_name
FROM information_schema.columns col
right join
information_schema.tables tab
ON col.table_name = tab.table_name
WHERE column_name = 'foo_id'
-- IN ('FOO_ID','BAR_FOO_ID') | or : like '%foo_id' | both works well most of the time
and tab.table_type = 'BASE TABLE'
But...
I am now with a table PLACES with the place_id column being referenced on at least 60 different constraints (matching LIKE '%place_id'). Then there is columns referencing the place id named otherwise like 'foo_currentplace','foo_storageroom', 'foo_lastrecomposition_place', 'operating_theatre' and so on. In the other hand, there is columns referring 'placetype_id' from placetype table which are LIKE '%place%' and I do NOT want to change the placetype_id, so we can not guess which column is to include or not only from their name.
I know there is the information_schema.table_constraints table, but it does NOT tell the referenced column.
If we can have the definition from the constraint name, it could be possible to match :
ILIKE format('%%REFERENCES %s(%s)%%',table_name,column_name)
but the definition isn't part of the table_constraints table either.
(For those wondering, I'm working on Hospital databases related to sterilization services.)
WHAT I WANT / TL;DR
I need a SELECT query (or a function definition ) returning all column of the whole database (schema_name,table_name,column_name) or (table_name,column_name) having a foreign key constraint referencing a specified column (parameter).
OK so I have done it :-)
The following query returns every column in database referencing FOO_TABLE.foo_column as foreign key:
SELECT
fk.table_schema as schema, --optional in my case, I only use public
fk.table_name as table,
substring(fk.constraint_def, 14, position(')' in constraint_def)-14) as column
FROM
(SELECT tc.*,
pg_get_constraintdef(c.oid) as constraint_def
--,c.oid
from pg_constraint c
left join information_schema.table_constraints tc
on c.conname = tc.constraint_name
where tc.constraint_type = 'FOREIGN KEY')
as fk
WHERE constraint_def ILIKE format('%%REFERENCES %s(%s)%%',
'FOO_TABLE','foo_column')
ORDER BY table_schema,table_name,3;
Test it there
I've found information_schema.table_constraints gets most of the information from pg_constraint which includes internal reference OID, and there is a built-in function pg_get_constraintdef() returning the definition of constraint object from it's OID.
Then, some substring of the definition is enough to extract the column_name AND
filter over the referenced column with the (I)LIKE filter I've prepared in my question.
----------------- OTHER ANSWER ------------------
Another acceptable query I've built from improving #Abelisto suggestion :
SELECT table_name, column_name
FROM (SELECT table_name, SUBSTR(column_name, 2, LENGTH(column_name)-2) as column_name,
referenced_table,SUBSTR(referenced_column, 2, LENGTH(referenced_column)-2) as referenced_column
FROM(select
conrelid::regclass::text as table_name,
(select array_agg(attname) from pg_attribute where conrelid = attrelid and attnum = any(conkey))::text as column_name,
confrelid::regclass::text as referenced_table,
(select array_agg(attname) from pg_attribute where confrelid = attrelid and attnum = any(confkey))::text as referenced_column
from pg_constraint where contype = 'f'
) b ) a
WHERE (referenced_table, referenced_column) = ('FOO_TABLE','foo_column');
Test it there
I don't think performances really matters there, so one should pick regarding what are the side needs. I think my first solution have the advantage to get the constraint definition if you want to alter it (say, for exemple, add a ON UPDATE CASCADE clause), yet the second seems more "compact" for this very purpose of just returning the table.column.
This is perhaps too long for a comment.
Postgres definitely supports cascading update constraints (see here). However, this is part of the definition of the constraint, not the update statement:
ALTER TABLE foo
ADD FOREIGN KEY fk_foo_bar_id FOREIGN KEY (bar_id) REFERENCES bar(bar_id)
ON UPDATE CASCADE;
----^ this is the important part
Note: You will need to redefine all your foreign key constraints to make them cascading update constraints.
And, as an editorial comment, I generally avoid cascading update foreign key constraints (because I don't like the idea of primary keys changing values). However, this is definitely a place where they are useful.
Then if you change bar.bar_id, the change will be reflected in foo. Here is a db<>fiddle.

How to list the columns of a view in Postgres?

For a physical table, I have been using the following SQL:
select column_name, data_type, character_maximum_length
from INFORMATION_SCHEMA.COLUMNS
where table_name = 'a_table_name'
I found that this doesn't work for a view. Is there a way to get the schema of a view by running a SQL command (not via psql).
Postgres has dedicated System Catalog Information Functions to help with that.
To get the full view definition:
SELECT pg_get_viewdef('public.view_name');
Schema-qualification is optional. If no schema is prefixed, the current search_path setting decides visibility.
A quick hack would be to just:
SELECT * FROM public.view_name LIMIT 0;
Depending on your client, column names and types should still be displayed. Or LIMIT n to get some sample values, too. The underlying query is actually executed then (unlike with LIMIT 0).
To list columns and their data type, in order, you might base the query on pg_attribute:
SELECT attname AS column_name, format_type(atttypid, atttypmod) AS data_type
FROM pg_attribute
WHERE attrelid = 'public.view_name'::regclass
-- AND NOT attisdropped
-- AND attnum > 0
ORDER BY attnum;
Type modifiers like maximum length are included in data_type this way.
Internally, a VIEW is implemented as special table with a rewrite rule. Details in the manual here. The table is saved in the system catalogs much like any regular table.
About the cast to regclass:
How to check if a table exists in a given schema
The same query works for tables or materialized views as well. Uncomment the additional filters above to only get visible user columns for tables.
SELECT
a.attname,
t.typname,
a.atttypmod
FROM pg_class c
INNER JOIN pg_attribute a ON a.attrelid = c.oid
INNER JOIN pg_type t ON t.oid = a.atttypid
WHERE c.relkind = 'v'
AND c.relname = 'put_viewname_here';
ATTENTION: Since the viewname is unique only in the schema, you might also want to add an INNER JOIN to pg_namespace and add a condition to the where-clause.
For the first version of your question:
SELECT n.nspname
FROM pg_class c
INNER JOIN pg_namespace n ON n.oid = c.relnamespace
WHERE c.relkind = 'v'
AND c.relname = 'put_viewname_here';
ATTENTION: This might give you multiple schemas, since a viewname is only unique inside a schema and thus a viewname does not always identify one view.

Check foreign table owner on Postgres

I have a foreign table on Postgres, linking to another server. I'm trying to select on this table, but I'm getting this error:
ERROR: permission denied for relation whitelist
Anyone knows how to check the ownership of a foreign table?
I've tried this, but it returns info just about local tables...
select t.table_name, t.table_type, c.relname, c.relowner, u.usename
from information_schema.tables t
join pg_catalog.pg_class c on (t.table_name = c.relname)
join pg_catalog.pg_user u on (c.relowner = u.usesysid)
where t.table_schema='schema_name';
Any admin tool should be able to tell you who owns a foreign table (or any other database object, for that matter). In pgAdmin, the owner appears in the Properties tab when you select the foreign table in the object browser, and psql will report the owner when you run \dE.
If you really need a query, this should do it:
SELECT
oid::regclass,
pg_get_userbyid(relowner)
FROM pg_class
WHERE relkind = 'f'

How can I list Foreign tables in PostgreSQL?

In PostgreSQL, running \d command will list the tables along with their table type. Currently I'm trying to list out all foreign tables that I've created using foreign data wrapper. What is the query to list out those tables?
Query for listing foreign tables only:
select * from information_schema.foreign_tables
According to the manual \dE[S+] should do it.
http://www.postgresql.org/docs/current/static/app-psql.html
To see the query behind this, start psql with the -e ("echo queries") option.
Or use the information_schema.tables view: http://www.postgresql.org/docs/current/static/infoschema-tables.html
The table_type column will contain FOREIGN TABLE for those tables.
You can also use this command:
\detr
SELECT tc.table_name , ctu.table_name
FROM information_schema.table_constraints tc
inner join information_schema.constraint_table_usage ctu on ctu.constraint_name = tc.constraint_name
where constraint_type = 'FOREIGN KEY'

Dynamically determining table name given field name in SQL server

Strange situation: I am trying to remove some hard coding from my code. There is a situation where I have a field, lets say "CityID", and using this information, I want to find out which table contains a primary key called CityID.
Logically, you'd say that it's probably a table called "City" but it's not... that table is called "Cities". There are some other inconsistencies in database naming hence I can never be sure if removing the string "ID" and finding out the plural will be sufficient.
Note: Once I figure out that CityID refers to a table called Cities, I will perform a join to replace CityID with city name on the fly. I will appreciate if someonw can also tell me how to find out the first varchar field in a table given its name.
SELECT name FROM sysobjects
WHERE id IN ( SELECT id FROM syscolumns WHERE name = 'THE_COLUMN_NAME' )
To get column information from the specified table:
SELECT column_name, data_type, character_maximum_length
FROM information_schema.columns
WHERE table_name = 'myTable'
select table_name from information_schema.columns where column_name='CityID'
You can use the INFORMATION_SCHEMA tables to read metadata about the database.
SELECT
TABLE_NAME
FROM
[db].[INFORMATION_SCHEMA].[COLUMNS]
WHERE
COLUMN_NAME='CityID';
For a primer in what's in the INFORMAITON_SCHEMA, see INFORMATION_SCHEMA, a map to your database
The information you seek is all available in the information schema views. Note that you will find many sources telling you how to directly query the underlying system tables that these are views onto - and I must admit that I do the same when it's just to find something out quickly - but the recommended way for applications is to go through these views.
For example, to find your CityID column:
SELECT * FROM INFORMATION_SCHEMA.COLUMNS WHERE COLUMN_NAME = 'CityID'
To find the first varchar field in a table:
SELECT TOP 1 * FROM INFORMATION_SCHEMA.COLUMNS WHERE
TABLE_NAME = 'TableName'
AND DATA_TYPE = 'varchar' -- This is off the top of my head!
ORDER BY ORDINAL_POSITION
As I understand from your question, you want to find tables which contain CITYID column in primary key
You can use SQL Server system views like sysindexes and sysindexkeys as shown in SQL tutorial to query database table primary keys including composite primary keys which are formed
SELECT
TBL.name as TableName
FROM sysobjects as PK
INNER JOIN sys.objects as TBL
on TBL.object_id = PK.parent_obj
INNER JOIN sysindexes as IND
on IND.name = PK.name AND
IND.id = TBL.object_id
INNER JOIN SysIndexKeys as KEYS
on KEYS.id = IND.id AND
KEYS.indid = IND.indid
INNER JOIN syscolumns as COL
on COL.id = KEYS.id AND
COL.colid = KEYS.colid
WHERE
PK.xtype = 'PK' AND
COL.name = 'CityID'