Retrieving column names from table -Redshift - sql

I have a table as below:
create table venue_ident
(venueid bigint identity(0, 1)NOT NULL,
venuename varchar(100) default 'city',
venuecity varchar(30),
venuestate char(2),
venueseats integer,
primary key(venueid));
Whenever I use the query
select DISTINCT c.column_name,
a.attencodingtype,
a.attnotnull,
a.atttypid::regtype,
a.attnum
FROM pg_attribute a , information_schema.columns c ,PG_TABLE_DEF as p
where attnum > 0
AND NOT attisdropped
AND c.ordinal_position=a.attnum
and c.column_name=a.attname
and c.table_name='venue_ident'
and a.attnotnull=p.notnull
ORDER by a.attnum;
It always outputs 6 columns instead of 5 . It shows primary key column (venue_id) twice with different values for not null condition.
How do i get just the 5 columns
(venueid, venuename, venuecity, venuestate, venueseats)

The pg_attribute table contains rows to represent primary keys etc. as well as columns. Since you've defined venueid as an IDENTITY column, there is an additional row for venueid that represents the identity property of the table.
You can see this by referencing pg_class in the query and looking at the value for relname:
SELECT
c.column_name,
a.attencodingtype,
a.attnotnull,
a.atttypid::regtype,
a.attnum,
pc.relname
FROM
pg_attribute a
INNER JOIN information_schema.columns c ON c.ordinal_position=a.attnum and c.column_name=a.attname
INNER JOIN pg_class pc ON a.attrelid = pc.oid
where
a.attnum > 0
AND NOT a.attisdropped
and c.table_name='venue_ident'
ORDER by a.attnum;
For one of the "venueid" rows, you'll see relname is "venue_ident_pkey" instead of "venue_ident".
If you want only the column names of the table, then add an additional WHERE clause filter on pc.relname='venue_ident' (the table name).

Related

How to know if a foreign key has cascade on delete clause

Due to a misconception of the PostgreSQL database I work with everyday, on the 155 tables that the schema of the database contains, some tables with foreign key doesn't have the 'on delete cascade' clause which cause serious trouble as you can expect.
I would like to correct this and with PGAdmin I'm able to see all FK of a table but not if the FK as the clause. Instead of, for each tables, dropping manually each FK and creating new ones with the 'on delete cascade', I would like to know how, for a specific table, the full definition of the foreign keys. Like this I will not drop foreign keys that already has the clause.
You can look in pg_constraint:
postgres=# create table car (id int primary key, name text);
CREATE TABLE
postgres=# create table driver (id int, car int references car(id) on delete cascade);
CREATE TABLE
postgres=# select connamespace, conname, c.relname as child_table, p.relname as parent_table, confdeltype
from pg_constraint
join pg_class c on c.oid=conrelid
join pg_class p on p.oid=confrelid;
connamespace | conname | child_table | parent_table | confdeltype
--------------+-----------------+-------------+--------------+-------------
2200 | driver_car_fkey | driver | car | c
(1 row)
This will show you all the foreign keys (along with their source and target tables) that do not have ON DELETE CASCADE:
select connamespace, conname, c.relname as child_table, p.relname as parent_table, confdeltype
from pg_constraint
join pg_class c on c.oid=conrelid
join pg_class p on p.oid=confrelid
where confdeltype <> 'c';
More information in the documentation
Disclosure: I work for EnterpriseDB (EDB)
This query will show all foreign constraints that are defined without cascading delete and the tables on which they are defined:
SELECT conname AS constraint_name,
conrelid::regclass AS table
FROM pg_constraint
WHERE contype = 'f'
AND confdeltype <> 'c';
Constraints can be queried from pg_constraint. Foreign key constraints have an 'f' in the column contype. The delete action can be taken from the column confdeltype. For cascading action it holds a 'c'. So you want all constraints where contype is 'f' and confdeltype isn't 'c'.
You can join pg_class for the involved tables and pg_namespace for their schemas. That way you can also limit the search to the tables of a specific schema.
In conkey the referencing and in confkey the referenced are stored as array of the ordinal numbers of the columns in the respective table. You can get the names from pg_attribute.
The following query would give you all foreign key constraints on any table in the schema public which's delete action isn't cascade along with the tables' schema names and the columns involved in the constraint.
SELECT con.conname,
con.confdeltype,
nsp.nspname,
rel.relname,
(SELECT array_agg(att.attname ORDER BY un.ord)
FROM unnest(con.conkey) WITH ORDINALITY un (attnum, ord)
INNER JOIN pg_attribute att
ON att.attnum = un.attnum
WHERE att.attrelid = rel.oid) conkeyattnames,
fnsp.nspname,
frel.relname,
(SELECT array_agg(att.attname ORDER BY un.ord)
FROM unnest(con.confkey) WITH ORDINALITY un (attnum, ord)
INNER JOIN pg_attribute att
ON att.attnum = un.attnum
WHERE att.attrelid = frel.oid) confkeyattnames
FROM pg_constraint con
INNER JOIN pg_class rel
ON rel.oid = con.conrelid
INNER JOIN pg_namespace nsp
ON nsp.oid = rel.relnamespace
INNER JOIN pg_class frel
ON frel.oid = con.confrelid
INNER JOIN pg_namespace fnsp
ON fnsp.oid = frel.relnamespace
WHERE con.contype = 'f'
AND con.confdeltype <> 'c'
AND nsp.nspname = 'public';

ORACLE SQL get all target table columns where source table is referenced as a FK

Using: Oracle SQL Developer
Hi I try to explain my Problem with a simple example:
I need a Oracle SQL Query that returns me all Foreign Key related columns from all child tables ( Table Employee and Table Building) that reference the parent table Table Organizational unit
The result for my example would look like this:
SELECT All COLUMNS OF All Tables THAT have an entry referenced as foreign key for table Table Organizational unit
WHERE Table Organizational unit.Code = 'HR'
--Result
Table Building
ID , ORG_UNIT_REF, Building Type
152, 2 , Main Building
Table Employee
ID, ORG_UNIT_REF, Employee Name
13, 2 , Max Doe
This means all Tables with their table name, column names and matching column contents have to be printed out.
I already found all the Referening tables and Constraint names by using this answer
SELECT a.table_name, a.column_name, a.constraint_name, c.owner,
-- referenced pk
c.r_owner, c_pk.table_name r_table_name, c_pk.constraint_name r_pk
FROM all_cons_columns a
JOIN all_constraints c ON a.owner = c.owner
AND a.constraint_name = c.constraint_name
JOIN all_constraints c_pk ON c.r_owner = c_pk.owner
AND c.r_constraint_name = c_pk.constraint_name
WHERE c.constraint_type = 'R'
AND a.table_name = :TableName
For my example the above query gives me something like that:
"TABLE_NAME","CONSTRAINT_NAME","STATUS","OWNER"
"Table Employee","FK_CONSTRAINT","ENABLED","TESTSCHEMA"
"Table Building","FK_CONST","ENABLED","TESTSCHEMA"
Now I know all the child tables that reference my parent table Organizational unit. Now I also want a query that fetches me all the rows in all the tables where the foreign key matches.

Does the column have foreign key references

I have a query :
SELECT
cl.relname AS table_name, a.attname AS column_name,
a.atttypid AS type_name, co.confkey AS keys
FROM
pg_class cl, pg_attribute a, pg_constraint co
WHERE
cl.oid = a.attrelid
AND co.conrelid = cl.oid
AND a.attnum > 0
ORDER BY
column_name
I have a database and there are o lot of tables inside, some of them has foreign keys (as I understand when the column from table 1 point on anouther column in table 2 it called, that first column has a foreign key, correct me if I'm wrong). So I need to show some information about every column of all the tables :
Name of the table
Name of the column
Type
does this column has a foreign key references?
I created small database and tested my query, results :
And as you see, foreign key is only for House column, but nope has the same value, and i need a mark only near House(from table2).
The main thing you're missing is a check for a.attnum = ANY(co.conkey). But there are a few other things you need to consider:
pg_class also contains indexes, views, sequences and types
pg_constraint also contains primary keys, CHECK constraints, etc.
Dropped columns are never removed from pg_attribute
The catalogs also describe the catalog tables themselves, which you probably don't care about
With all of that in mind:
SELECT
n.nspname AS schema_name,
cl.relname AS table_name,
a.attname AS column_name,
a.atttypid AS type_name,
co.confkey AS keys
FROM
pg_class cl
JOIN pg_namespace n ON
n.oid = cl.relnamespace
JOIN pg_attribute a ON
a.attrelid = cl.oid
LEFT JOIN pg_constraint co ON
co.contype = 'f' AND
co.conrelid = cl.oid AND
a.attnum = ANY(co.conkey)
WHERE
n.nspname NOT IN ('pg_catalog', 'information_schema') AND
cl.relkind = 'r' AND
a.attnum > 0 AND
NOT a.attisdropped

Find referenced field(s) of foreign key constraint

I have a table Users with a field called org_id which is a foreign key to a table organisation, with primary key field organisation_id. Knowing the table name (users) and the field name (users.org_id), is there a query that can tell me the name and field that org_id references?
I've found a Stackoverflow post similar to this where a query was provided to determine the referenced table name, but I also need to know the field name that is referenced:
SELECT c.confrelid::regclass::text AS referenced_table
,c.conname AS fk_name
,pg_get_constraintdef(c.oid) AS fk_definition
FROM pg_attribute a
JOIN pg_constraint c ON (c.conrelid, c.conkey[1]) = (a.attrelid, a.attnum)
WHERE a.attrelid = '"Schema"."Users"'::regclass -- table name
AND a.attname = 'org_id' -- column name
AND c.contype = 'f'
ORDER BY conrelid::regclass::text, contype DESC;
So the above query would return the name of the table (organisation), the fk name and fk definition. Is there a way to also get the name of the field that is referenced? I know I could probably perform another query to determine the name of pk given a table but I would like to avoid performing multiple queries for this.
This query adds the referenced column(s) for the foreign key constraint:
SELECT c.confrelid::regclass::text AS referenced_table
,string_agg(f.attname, ', ') AS referenced_columns
,c.conname AS fk_name
,pg_get_constraintdef(c.oid) AS fk_definition
FROM pg_attribute a
JOIN pg_constraint c ON (c.conrelid, c.conkey[1]) = (a.attrelid, a.attnum)
JOIN pg_attribute f ON f.attrelid = c.confrelid
AND f.attnum = ANY (confkey)
WHERE a.attrelid = '"Schema"."Users"'::regclass -- table name
AND a.attname = 'org_id' -- column name
AND c.contype = 'f'
GROUP BY c.confrelid, c.conname, c.oid;
A fk constraint can reference multiple columns. That's the reason for the aggregate function string_agg() in the query.

NOT to soft delete a row in a table that contain foreign key to other tables

I am doing soft delete in all my tables. I should not soft delete a row when that ID is referred in other tables. Also, when the referred child table is deleted i.e, Isdeleted = 1, then I should be able to soft delete the parent record.
Your suggestions are appreciated.
You'll need to generate some dynamic sql from the schema. I don't have time to pivot all the items into dynamic sql here, but you could use either a cursor loop or possibly PIVOT for the dynamic SQL:
-- parent/child schemas, tables, columns
select parent_schema=p.TABLE_SCHEMA
, parent_table=p.TABLE_NAME
, parent_pk_column=p.COLUMN_NAME
, child_schema=c.TABLE_SCHEMA
, child_table=c.TABLE_NAME
, child_fk_column=c.COLUMN_NAME
from INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE p
inner join INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS pc
on pc.UNIQUE_CONSTRAINT_SCHEMA=p.CONSTRAINT_SCHEMA
and pc.UNIQUE_CONSTRAINT_NAME=p.CONSTRAINT_NAME
inner join INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE c
on c.CONSTRAINT_SCHEMA=pc.CONSTRAINT_SCHEMA
and c.CONSTRAINT_NAME=pc.CONSTRAINT_NAME
where exists(
select 1 from INFORMATION_SCHEMA.COLUMNS
where COLUMN_NAME='IsDeleted' and TABLE_SCHEMA=p.TABLE_SCHEMA and TABLE_NAME=p.TABLE_NAME
)
-- tables/pk columns having IsDeleted column but no children
select parent_schema=p.TABLE_SCHEMA
, parent_table=p.TABLE_NAME
, parent_column=p.COLUMN_NAME
from INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE p
where not exists(
select 1 from INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS
where UNIQUE_CONSTRAINT_SCHEMA=p.CONSTRAINT_SCHEMA
and UNIQUE_CONSTRAINT_NAME=p.CONSTRAINT_NAME
)
and exists(
select 1 from INFORMATION_SCHEMA.COLUMNS
where COLUMN_NAME='IsDeleted' and TABLE_SCHEMA=p.TABLE_SCHEMA and TABLE_NAME=p.TABLE_NAME
)