How to find dependencies of a view - postgresql

I need to find all the views and tables dependencies from a view, ideally like a tree diagram. Is that possible? I used pg_depend but it didn't seems to work. i also used this script that i found.
SELECT v.oid::regclass AS view
FROM pg_depend AS d -- objects that depend on the table
JOIN pg_rewrite AS r -- rules depending on the table
ON r.oid = d.objid
JOIN pg_class AS v -- views for the rules
ON v.oid = r.ev_class
WHERE v.relkind = 'v' -- only interested in views
-- dependency must be a rule depending on a relation
AND d.classid = 'pg_rewrite'::regclass
AND d.refclassid = 'pg_class'::regclass
AND d.deptype = 'n' -- normal dependency
AND d.refobjid = 'schema.viewname'::regclass;
But also didn't seems to work as i need to.
Do you have any idea?
Thanks in advance!
Edit :
WHERE v.relkind = 'v' and v.relkind = 'r' -- only interested in views and tables
I added the v.relkind = 'r' but it still seems not to work

Related

what is partition_position in all_tab_partitions

Anyone can Explain what is partition_position in all_tab_partitions.
And anyone can tell me what is conversion of this
SELECT partition_position
FROM all_tab_partitions tp
WHERE tp.table_owner = ? AND
tp.table_name = ? AND
tp.partition_name = ?
to Postgres.
ALL_TAB_PARTITIONS
Column
Datatype
Description
PARTITION_POSITION
NUMBER
Position of the partition within the table
I don't know how (if anyhow) it can be translated from Oracle to PostgreSQL.
You can convert oracle queries like below (maybe it's not like that but I think it helps you):
Postgres doesn't have partition_position column and should create manually based on table object id
WITH partition_info as (
SELECT nmsp_parent.nspname AS parent_schema,
parent.relname AS parent,
owner_parent.rolname AS parent_owner,
nmsp_child.nspname AS child_schema,
child.relname AS child,
owner_child.rolname AS child_owner,
row_number() OVER (PARTITION BY parent.relname ORDER BY child.oid) AS partition_position
FROM pg_inherits
JOIN pg_class parent ON pg_inherits.inhparent = parent.oid
JOIN pg_class child ON pg_inherits.inhrelid = child.oid
JOIN pg_namespace nmsp_parent ON nmsp_parent.oid = parent.relnamespace
JOIN pg_namespace nmsp_child ON nmsp_child.oid = child.relnamespace
JOIN pg_authid owner_parent ON owner_parent.oid = parent.relowner
JOIN pg_authid owner_child ON owner_child.oid = child.relowner
)
SELECT partition_position
FROM partition_info
WHERE child_owner = ? -- table_owner
AND parent = ? -- partition_name
AND child = ? -- table_name
PostgreSQL doesn't have a concept of order in the list of partitions for a table, and indeed it wouldn't make sense in all cases. What if the partitioning key is a data type that doesn't have a total ordering, like polygon? I admit that that is an unusual data type to partition by, but it could be used with list partitioning.

Unable to improve query performance in postgresql

I am trying to join 9 tables together. The count and index of each tables are given below along with the query. Green color in screenshot indicates keys used to join. But please note that I have used another column for visit_occurrence table called visit_occurrence_id to join but it's not indexed
DROP MATERIALIZED VIEW IF EXISTS cdm.dummy CASCADE;
CREATE MATERIALIZED VIEW cdm.dummy as
select
f.person_id,f.gender_id
from cdm.visit_occurrence a
left join
cdm.condition_occurrence b
on a.person_id = b.person_id and a.visit_occurrence_id =
b.visit_occurrence_id
left join
cdm.measurement c
on a.person_id = c.person_id and a.visit_occurrence_id =
c.visit_occurrence_id
left join
cdm.drug_exposure d
on a.person_id = d.person_id and a.visit_occurrence_id =
d.visit_occurrence_id
left join
cdm.procedure_occurrence e
on a.person_id = e.person_id and a.visit_occurrence_id =
e.visit_occurrence_id
left join
cdm.person f
on a.person_id = f.person_id
left join
cdm.observation g
on a.person_id = g.person_id and a.visit_occurrence_id =
g.visit_occurrence_id
left join
cdm.observation_period h
on a.person_id = g.person_id
left join
cdm.death i
on a.person_id = i.person_id
explain output
explain outpt with enable_nestloop = off;
Please note that visit_occurrence is the base table. I pick the columns person_id and visit_occurrence_id from visit_occurrence table to join with other tables as shown in the query. I see that visit_occurrence_id used to join (from base table) with other tables isn't a index column (in base table).
a) Is this the reason for slow performance because it's a base table? But in all other tables, the joining keys are used as index as shown in screenshot above(green color indicates - keys used to join)
b) Are the records count an issue?
Can you help me adapt my query to fix this?
Its been running for more than 5-6 hours but not output yet.
Any help is much appreciated. Will be really helpful

How to get the list of column names for all indexes on a table in PostgreSQL?

I have this query to get the list of indexes on a table:
SELECT
ns.nspname as schema_name,
tab.relname as table_name,
cls.relname as index_name,
am.amname as index_type,
idx.indisprimary as is_primary,
idx.indisunique as is_unique
FROM
pg_index idx
INNER JOIN pg_class cls ON cls.oid=idx.indexrelid
INNER JOIN pg_class tab ON tab.oid=idx.indrelid
INNER JOIN pg_am am ON am.oid=cls.relam
INNER JOIN pg_namespace ns on ns.oid=tab.relnamespace
WHERE ns.nspname = #Schema AND tab.relname = #Name
It seems to be working right. But now I need a query for the list of columns and I'm having trouble understanding how the system views work.
Specifically what I'm looking for are:
[index name or id for matching to the first query]
Order in index
Column name
ascending or descending
sorted column or included column
Ideally I would like to get the above items for all indexes of a given table at one time.
Note that I'm looking for more than just the column names.
Use the system catalog information function pg_get_indexdef(index_oid) to get complete information (including the list of index expressions) - in a query against pg_index to get all indexes for a given table:
SELECT pg_get_indexdef(indexrelid) || ';' AS idx
FROM pg_index
WHERE indrelid = 'public.tbl'::regclass; -- optionally schema-qualified
Related:
Django/PostgreSQL varchar to UUID
Copy indexes from one table to another
If you rely on an unqualified table name (without schema) you depend on the current search_path setting and might get results for a table of the same name in a different schema.
Alternatively, you can join to pg_attribute by hand to get individual columns like demonstrated in these related answers:
How to get column attributes query from table name using PostgreSQL?
Find tables with multiple indexes on same column
Key ingredient is to join like this:
FROM pg_index idx
LEFT JOIN pg_attribute a ON a.attrelid = idx.indrelid
AND a.attnum = ANY(idx.indkey)
AND a.attnum > 0
The manual about pg_index.indkey:
This is an array of indnatts values that indicate which table columns
this index indexes. For example a value of 1 3 would mean that the
first and the third table columns make up the index entries. Key
columns come before non-key (included) columns. A zero in this array
indicates that the corresponding index attribute is an expression over
the table columns, rather than a simple column reference.
Adding AND a.attnum > 0 is not technically necessary as there is no a.attnum = 0. But it makes the query clearer and it won't hurt. The manual:
Ordinary columns are numbered from 1 up. System columns, such as oid, have (arbitrary) negative numbers.
Be aware, that there the "list of column names" can actually contain expressions, too. And since Postgres 11 there are also "included" columns (no expressions there). pg_get_indexdef() deals with all possible complications out of the box.
You can puzzle it together from the system catalogs, as Erwin Brandstetter detailed.
Here is a query that will return the information you want:
SELECT i.indexrelid::regclass AS indexname,
k.i AS index_order,
i.indnkeyatts,
coalesce(a.attname,
(('{' || pg_get_expr(
i.indexprs,
i.indrelid
)
|| '}')::text[]
)[k.i]
) AS index_column,
i.indoption[k.i - 1] = 0 AS ascending,
k.i <= i.indnkeyatts AS is_key
FROM pg_index i
CROSS JOIN LATERAL unnest(i.indkey) WITH ORDINALITY AS k(attnum, i)
LEFT JOIN pg_attribute AS a
ON i.indrelid = a.attrelid AND k.attnum = a.attnum
WHERE i.indrelid = 'schemaname.tablename'::regclass;
This query will only work from PostgreSQL v11 on (but there are no covering Indexes before v11).
Also, the query will fail if the indexed expression contains a comma; I don't know how to fix that.
Version 10.4
SELECT idx.indexrelid::regclass AS indexname,
k.i AS index_order,
--i.indnkeyatts,
coalesce(att.attname,
(('{' || pg_get_expr(
idx.indexprs,
idx.indrelid
)
|| '}')::text[]
)[k.i]
) AS index_column,
pg_index_column_has_property(idx.indexrelid,k.i::int,'asc') AS ascending,
k.i != -1 AS is_key
FROM pg_index idx
CROSS JOIN LATERAL unnest(idx.indkey) WITH ORDINALITY AS k(attnum, i)
LEFT JOIN pg_attribute AS att
ON idx.indrelid = att.attrelid AND k.attnum = att.attnum

PostgreSQL: List of views/table rules that depend on a given table

How can I find all Views and Tables with rules which depend on a given Table?
I need this in order to find which views and tables I have to check if I want to alter/drop that given Table.
Get Views or Tables which refer to a given table TABLENAME:
SELECT cl_r.relname AS ref_table
FROM pg_rewrite AS r
JOIN pg_class AS cl_r ON r.ev_class=cl_r.oid
JOIN pg_depend AS d ON r.oid=d.objid
JOIN pg_class AS cl_d ON d.refobjid=cl_d.oid
WHERE cl_d.relkind IN ('r','v') AND cl_d.relname='TABLENAME'
GROUP BY cl_r.relname
ORDER BY cl_r.relname;
I did it by reversing the following answer: https://stackoverflow.com/a/4337615
If I understand correctly, you want the rules not the relations. If you want the custom defined ones you can:
SELECT * from pg_rules WHERE tablename = 'TABLENAME'
if you want to see the system defines ones (for examples the one from the views) you can:
SELECT
N.nspname AS schemaname,
C.relname AS tablename,
R.rulename AS rulename,
pg_get_ruledef(R.oid) AS definition
FROM (pg_rewrite R JOIN pg_class C ON (C.oid = R.ev_class))
LEFT JOIN pg_namespace N ON (N.oid = C.relnamespace)
WHERE C.relname = 'TABLENAME';
I just took the query from the definition of pg_rules that is actually a system view (with \d+ pg_rules), and changed the WHERE clause, that is normally:
WHERE r.rulename <> '_RETURN'::name;

In PostgreSQL, How to find which table uses specific Sequence?

I have a sequence called seque_post.
I need to find out in what table it's being used.
Is there a way to write a query that will give the table name?
I wrote this query to find the sequence:
select *
from pg_class
where relname like 'seque_post'
there is a filed there reltoastrelid which according to the manual gives:
OID of the TOAST table associated with this table, 0 if none. The TOAST table stores large attributes "out of line" in a secondary table.
but i'm not sure how to continue from here.. suggestions?
To find the table a sequence is "related" to, you can use something like this:
select seq_ns.nspname as sequence_schema,
seq.relname as sequence_name,
tab_ns.nspname as table_schema,
tab.relname as related_table
from pg_class seq
join pg_namespace seq_ns on seq.relnamespace = seq_ns.oid
JOIN pg_depend d ON d.objid = seq.oid AND d.deptype = 'a'
JOIN pg_class tab ON d.objid = seq.oid AND d.refobjid = tab.oid
JOIN pg_namespace tab_ns on tab.relnamespace = tab_ns.oid
where seq.relkind = 'S'
and seq.relname = '[your sequence name]'
and seq_ns.nspname = 'public';
Just to complete the picture:
The other way round (looking up a sequence for a column) is easier, because Postgres has a function to find the sequence for a column:
select pg_get_serial_sequence('public.some_table', 'some_column');
The key catalog here is the rather versatile pg_depend, which can connect basically any two items of any sort.
The ::regclass cast is a magic trick for converting to and from oids, which allows you to look up something like this, with no joins (but possible ambiguities):
select
D.refobjid::regclass, -- the target table name
D.* -- see docs for meaning of other columns
from
pg_depend as D
where
-- source is a relation (in this case, a sequence)
D.classid = 'pg_catalog.pg_class'::regclass
-- target is also a relation (in this case, a table)
and D.refclassid = 'pg_catalog.pg_class'::regclass
-- source is the sequence you're looking for, fully qualified name
and D.objid = 'public.seque_post'::regclass
Try this using pg_depend instead of pg_class:
SELECT d.refobjid::regclass, a.attname
FROM pg_depend d
JOIN pg_attribute a ON a.attrelid = d.refobjid AND a.attnum = d.refobjsubid
WHERE d.objid = 'public."seque_post"'::regclass;
If you add the join to pg_attribute then you even have the column name that uses the sequence.
The ::regclass cast can be used to magically convert object identifiers to relation names.
Hope that helps.