I got these three giant schema in Oracle which I call them db layers (L3, L2, L1).
In each layer I got many SPs which might call some procedures from their underlying layers. Now for documentation purposes I need to draw something like a tree to show these chain calls. Well I'm not interested to get involved in the drudgery of extracting this data manually.
The question is, is there an automated way to do this? like a query to find out who calls who.
I was just fiddling around a little. So maybe like a starting point.
Replace DBA_OBJECTS.OWNER IN ('HUSQVIK') with your schemas.
WITH leafs AS (
SELECT
DBA_OBJECTS.OWNER, DBA_OBJECTS.OBJECT_NAME NAME,
CASE WHEN COUNT(PARENT_REFERENCES.REFERENCED_NAME) > 0 THEN 1 ELSE 0 END IS_REFERENCED,
CASE WHEN COUNT(CHILD_REFERENCES.NAME) > 0 THEN 1 ELSE 0 END HAS_REFERENCES
FROM
DBA_OBJECTS
LEFT JOIN DBA_DEPENDENCIES PARENT_REFERENCES ON DBA_OBJECTS.OWNER = PARENT_REFERENCES.REFERENCED_OWNER AND DBA_OBJECTS.OBJECT_NAME = PARENT_REFERENCES.REFERENCED_NAME
LEFT JOIN DBA_DEPENDENCIES CHILD_REFERENCES ON DBA_OBJECTS.OWNER = CHILD_REFERENCES.OWNER AND DBA_OBJECTS.OBJECT_NAME = CHILD_REFERENCES.NAME
WHERE
OBJECT_TYPE IN ('PACKAGE BODY', 'FUNCTION', 'PROCEDURE')
AND DBA_OBJECTS.OWNER IN ('HUSQVIK')
GROUP BY
DBA_OBJECTS.OWNER, DBA_OBJECTS.OBJECT_NAME
)
SELECT 'Entry point -> ' || OWNER || '.' || NAME DEPENDENCY_PATH, 1 MAX_STACK_DEPTH FROM leafs WHERE leafs.IS_REFERENCED = 0 AND leafs.HAS_REFERENCES = 0
UNION ALL
SELECT
DEPENDENCY_PATH, STACK_DEPTH
FROM (
SELECT
'Entry point -> ' ||
CONNECT_BY_ROOT DBA_DEPENDENCIES.OWNER || '.' || CONNECT_BY_ROOT DBA_DEPENDENCIES.NAME ||
SYS_CONNECT_BY_PATH(DBA_DEPENDENCIES.REFERENCED_OWNER || '.' || DBA_DEPENDENCIES.REFERENCED_NAME, ' -> ') DEPENDENCY_PATH,
CONNECT_BY_ISLEAF ISLEAF,
LEVEL + 1 STACK_DEPTH
FROM
DBA_DEPENDENCIES
LEFT JOIN
(SELECT * FROM leafs WHERE leafs.IS_REFERENCED = 0) roots
ON roots.OWNER = DBA_DEPENDENCIES.OWNER AND roots.NAME = DBA_DEPENDENCIES.NAME
WHERE
DBA_DEPENDENCIES.REFERENCED_TYPE IN ('PACKAGE BODY', 'FUNCTION', 'PROCEDURE')
START WITH
roots.NAME IS NOT NULL
CONNECT BY NOCYCLE
PRIOR DBA_DEPENDENCIES.REFERENCED_OWNER = DBA_DEPENDENCIES.OWNER AND
PRIOR DBA_DEPENDENCIES.REFERENCED_NAME = DBA_DEPENDENCIES.NAME)
WHERE ISLEAF = 1
Get all dependencies of your schema with this query:
select * from all_dependencies where owner = 'your_schema_name'
Export result of query to JSON (or any other format).
Process JSON of dependencies to generate tree(s).
Related
I have this query, and one of its column is a subquery that should be bringing a list of values using a listagg function. This list has its starting point as the S.ID_ORGAO_INTELIGENCIA value. The list is a should be, it always has values.
The listagg function is consuming an inline view that uses a window function to create the list.
select *
from (
SELECT DISTINCT S.ID_SOLICITACAO,
S.NR_PROTOCOLO_SOLICITACAO,
S.DH_INCLUSAO,
S.ID_USUARIO,
U.NR_CPF,
OI.ID_MODULO,
OI.ID_ORGAO_INTELIGENCIA,
OI.NO_ORGAO_INTELIGENCIA,
R.ID_ATRIBUICAO,
P.ID_PERMISSAO,
1 AS TIPO_NOTIFICACAO,
(
select LISTAGG(oc6.ID_ORGAO_INTELIGENCIA || '-' || oc6.ord || '-', '; ') WITHIN GROUP (ORDER BY oc6.ord) eai
from (
SELECT oc1.ID_ORGAO_INTELIGENCIA,
oc1.ID_ORGAO_INTELIGENCIA_PAI,
oc1.SG_ORGAO_INTELIGENCIA,
rownum as ord
FROM TB_ORGAO_INTERNO oc1
WHERE oc1.DH_EXCLUSAO is null
-- THE VALUE FROM S.ID_ORGAO_INTELIGENCIA IS NOT AVAILBLE HERE
START WITH oc1.ID_ORGAO_INTELIGENCIA = S.ID_ORGAO_INTELIGENCIA
CONNECT BY prior oc1.ID_ORGAO_INTELIGENCIA_PAI = oc1.ID_ORGAO_INTELIGENCIA
) oc6) aproPrec
FROM TB_SOLICITACAO S
INNER JOIN TB_ORGAO_INTERNO OI ON S.ID_ORGAO_INTELIGENCIA = OI.ID_ORGAO_INTELIGENCIA
INNER JOIN TB_RELACIONAMENTO_ATRIBUICAO R
ON (R.ID_MODULO = OI.ID_MODULO AND R.ID_ORGAO_INTELIGENCIA IS NULL AND
R.ID_SOLICITACAO IS NULL)
INNER JOIN TB_PERMISSAO P
ON (P.ID_USUARIO = :usuario AND P.ID_ORGAO_INTELIGENCIA = :orgao AND
P.ID_ATRIBUICAO = R.ID_ATRIBUICAO)
INNER JOIN TB_USUARIO U ON (U.ID_USUARIO = S.ID_USUARIO)
WHERE 1 = 1
AND U.DH_EXCLUSAO IS NULL
AND P.DH_EXCLUSAO IS NULL
AND S.DH_EXCLUSAO IS NULL
AND OI.DH_EXCLUSAO IS NULL
AND R.ID_ATRIBUICAO IN :atribuicoes
AND P.ID_STATUS_PERMISSAO = 7
AND OI.ID_MODULO = 1
AND S.ID_STATUS_SOLICITACAO IN (1, 2, 5, 6)
and s.ID_ORGAO_INTELIGENCIA in (SELECT DISTINCT o.ID_ORGAO_INTELIGENCIA
FROM TB_ORGAO_INTERNO o
WHERE o.DH_EXCLUSAO IS NULL
START WITH o.ID_ORGAO_INTELIGENCIA = 3
CONNECT BY PRIOR o.ID_ORGAO_INTELIGENCIA = o.ID_ORGAO_INTELIGENCIA_PAI)
);
The problem is that the aproPrec column is always returning null as its result.
If I force the criteria to have the S.ID_ORGAO_INTELIGENCIA hardcoded, the list returns its true value.
If I chance this:
START WITH oc1.ID_ORGAO_INTELIGENCIA = S.ID_ORGAO_INTELIGENCIA
To this:
START WITH oc1.ID_ORGAO_INTELIGENCIA = 311
where 311 is the value that the S.ID_ORGAO_INTELIGENCIA column really has.
Is there a way to make this query works as 'I think' it should work?
To make it work, I changed the subquery by this another one:
(
select qt_.*
from (
SELECT QRY_NAME.*,
rownum as ord
FROM (
SELECT oc1.ID_ORGAO_INTELIGENCIA,
oc1.ID_ORGAO_INTELIGENCIA_PAI,
connect_by_root (oc1.ID_ORGAO_INTELIGENCIA) as root
FROM TB_ORGAO_INTERNO oc1
CONNECT BY NOCYCLE PRIOR oc1.ID_ORGAO_INTELIGENCIA_PAI = oc1.ID_ORGAO_INTELIGENCIA
) QRY_NAME
WHERE root = s.ID_ORGAO_INTELIGENCIA
) qt_
)
I need a query to find whether index bloat on a table. I saw some queries where they are comparing table size with index size. If there is any other approach, please share the query.
I am using Greenplum 4.3 (which is based Postgres 8.2)
Bloat Score Query
The following SQL query will examine each table in the XML schema and identify dead rows (tuples) that are wasting disk space.
SELECT schemaname || '.' || relname as tblnam,
n_dead_tup,
(n_dead_tup::float / n_live_tup::float) * 100 as pfrag
FROM pg_stat_user_tables
WHERE schemaname = 'xml' and n_dead_tup > 0 and n_live_tup > 0 order by pfrag desc;
If this query returns a high percentage ( pfrag ) of dead tuples, the VACUUM command may be used to reclaim space.
7 Considered to be high
From wiki.postgres.org
SELECT
current_database(), schemaname, tablename, /*reltuples::bigint, relpages::bigint, otta,*/
ROUND((CASE WHEN otta=0 THEN 0.0 ELSE sml.relpages::float/otta END)::numeric,1) AS tbloat,
CASE WHEN relpages < otta THEN 0 ELSE bs*(sml.relpages-otta)::BIGINT END AS wastedbytes,
iname, /*ituples::bigint, ipages::bigint, iotta,*/
ROUND((CASE WHEN iotta=0 OR ipages=0 THEN 0.0 ELSE ipages::float/iotta END)::numeric,1) AS ibloat,
CASE WHEN ipages < iotta THEN 0 ELSE bs*(ipages-iotta) END AS wastedibytes
FROM (
SELECT
schemaname, tablename, cc.reltuples, cc.relpages, bs,
CEIL((cc.reltuples*((datahdr+ma-
(CASE WHEN datahdr%ma=0 THEN ma ELSE datahdr%ma END))+nullhdr2+4))/(bs-20::float)) AS otta,
COALESCE(c2.relname,'?') AS iname, COALESCE(c2.reltuples,0) AS ituples, COALESCE(c2.relpages,0) AS ipages,
COALESCE(CEIL((c2.reltuples*(datahdr-12))/(bs-20::float)),0) AS iotta -- very rough approximation, assumes all cols
FROM (
SELECT
ma,bs,schemaname,tablename,
(datawidth+(hdr+ma-(case when hdr%ma=0 THEN ma ELSE hdr%ma END)))::numeric AS datahdr,
(maxfracsum*(nullhdr+ma-(case when nullhdr%ma=0 THEN ma ELSE nullhdr%ma END))) AS nullhdr2
FROM (
SELECT
schemaname, tablename, hdr, ma, bs,
SUM((1-null_frac)*avg_width) AS datawidth,
MAX(null_frac) AS maxfracsum,
hdr+(
SELECT 1+count(*)/8
FROM pg_stats s2
WHERE null_frac<>0 AND s2.schemaname = s.schemaname AND s2.tablename = s.tablename
) AS nullhdr
FROM pg_stats s, (
SELECT
(SELECT current_setting('block_size')::numeric) AS bs,
CASE WHEN substring(v,12,3) IN ('8.0','8.1','8.2') THEN 27 ELSE 23 END AS hdr,
CASE WHEN v ~ 'mingw32' THEN 8 ELSE 4 END AS ma
FROM (SELECT version() AS v) AS foo
) AS constants
GROUP BY 1,2,3,4,5
) AS foo
) AS rs
JOIN pg_class cc ON cc.relname = rs.tablename
JOIN pg_namespace nn ON cc.relnamespace = nn.oid AND nn.nspname = rs.schemaname AND nn.nspname <> 'information_schema'
LEFT JOIN pg_index i ON indrelid = cc.oid
LEFT JOIN pg_class c2 ON c2.oid = i.indexrelid
) AS sml
ORDER BY wastedbytes DESC
There is an ability to query tree in Oracle with clauses CONNECT BY and START WITH.
For example:
SELECT RPAD (' ', (LEVEL - 1) * 4) || node_name AS node, LEVEL
FROM hierarchy
START WITH NVL (pig_ear_id, 0) = 0
CONNECT BY PRIOR id = pig_ear_id;
The query result can be simply filtered to show the only nodes which accepted by filter predicate or located on the path to root:
SELECT RPAD (' ', (LEVEL - 1) * 4) || node_name AS node, LEVEL
FROM hierarchy
START WITH NVL (pig_ear_id, 0) = 0
CONNECT BY PRIOR id = pig_ear_id AND id IN (
SELECT id
FROM hierarchy
START WITH node_name = 'some-pattern'
CONNECT BY PRIOR pig_ear_id = id
);
A similar select in PostgreSQL will be built with clause WITH RECURSIVE .... As I understand one with-query can not be included in other with-query to get same filtered result as Oracle allows.
How to rewrite the second select in PostgreSQL?..
As I understand one with-query can not be included in other with-query
Of course you can, just write one after the other:
with recursive valid_nodes as (
-- this is the inner "CONNECT BY" query from your example
select id
from hierarchy
where node_name = 'some-pattern'
union all
select c.id
from hierarchy c
join valid_nodes p on c.id = p.pig_ear_id
), final_tree as (
-- this is outer query from your example
select node_name as node, 1 as level
from hierarchy
where NVL (pig_ear_id, 0) = 0
union all
select c.node_name, p.level + 1
from hierarchy c
join final_tree p on p.id = c.pig_ear_id
where id in (select id from valid_nodes) -- and here we re-use the previous CTE
)
select rpad(node, level - 1)||node, level
from final_tree;
Note the recursive keyword only needs to be stated at the beginning. Regardless on how many recursive CTEs you have (but you need to have at least one in the CTE chain, if you use it).
If you have a with query that is calling some function and that function in turn has a with query,
then it allows us and not raise any error...in that way we still able to have nested with query.
so typically i created a query using with clause. see the first query below.
It has in clause which has select query that is selecting records returned by the functions(my_function).
and the function has another hierarchical with query.
Also i do not know what you want to return from your query.so change query as u need.This is just the way to achieve required structure.
Below is the syntax for sql server.Change appropriately for any other database.
with alias_list
(
pig_ear_id,
node_name,
id
) as (
select pig_ear_id, node_name, id
from hierarchy
where pig_ear_id = ?
union all
select b.pig_ear_id, node_name, id
from alias_list a, hierarchy b
where a.pig_ear_id = b.id
and id in (select id from my_function('some-pattern')))
select * from alias_list;
==============================================================
create function my_function(#node_name varchar(40))
returns #temptable table
(
id varchar(40)
)
as
begin
with alias_list
(
pig_ear_id,
node_name,
id
) as (
select pig_ear_id, node_name, id
from hierarchy
where node_name = ?
union all
select b.pig_ear_id, node_name, id
from alias_list a, hierarchy b
where a.id = b.pig_ear_id)
insert into #temptable select * from alias_list;
return
end
================================================================
I have table like this
Table- A
Conversion_logic Output_param
func(a,b) c
func(d) e
func(c) d
func(e) f
Here rows depicts that func(a,b) gives me "c", now this "c" is applied as func(c) and gives me "d", now this "d" is applied as func(d) and gives me "e" and now this "e" is applied as func(e) which gives me "f"
So I want an output like this
1) That row should be the first row whose output has no dependency.
2) From there it should follow parent child relation
Conversion_logic Output_param
func(e) f
func(d) e
func(c) d
func(a,b) c
You can use hierarchical queries.
SELECT table_name.*
FROM table_name
CONNECT BY PRIOR conversion_logic = 'func(' || output_param || ')'
START WITH conversion_logic = 'func(e)';
UPDATE:
SELECT table_name.*
FROM table_name
CONNECT BY PRIOR conversion_logic = 'func(' || ooutput_param || ')'
START WITH ooutput_param =
(SELECT a.ooutput_param
FROM table_name a
WHERE 'func(' || a.ooutput_param || ')' NOT IN (
SELECT b.conversion_logic
FROM table_name b));
Not sure about the performance of this query. Maybe there are better and efficient ones.
Try
SELECT t1.*
FROM taba t1
LEFT OUTER JOIN taba t2 ON instr(replace(t1.Conversion_logic, 'func'), t2.Output_param) > 0
START WITH t2.Conversion_logic IS NULL
CONNECT BY instr(replace(t1.Conversion_logic, 'func'), PRIOR t1.Output_param) > 0
ORDER BY LEVEL DESC
Here is a sqlfiddle demo
Not sure the title explains the problem well; this is what I'm working with,
I have the following tables,
-- table = kms_doc_ref_currnt_v
DOC_ID VARCHAR2(19)
TO_DOC_ID VARCHAR2(19)
BRANCH_ID NUMBER(8)
REF_TYP_CD VARCHAR2(20)
-- table = kms_fil_nm_t
DOC_ID VARCHAR2(19) PRIMARY KEY UNIQUE
For example, I can get a count of all kms_doc_ref_currnt_v records that have a to_doc_id = 59678, where 59678 is one value in kms_fil_nm_t, with this query,
select 'doc_id 59678 has ' || count(to_doc_id) as cnt from kms_doc_ref_currnt_v where branch_id=1 and ref_typ_cd in ('CONREF', 'KBA') and to_doc_id=59678;
kms_doc_ref_currnt_v.to_doc_id is a field that has one of the kms_fil_nm_t.doc_id values. kms_doc_ref_currnt_v.doc_id is also one of the values in kms_fil_nm_t.
The single query I'm looking for would loop over each kms_fil_nm_t.doc_id and count all the rows in kms_doc_ref_currnt_v that have a similar to_doc_id. Each row returned would look like the output of the query above. Here's example output,
doc_id 1 has 32
doc_id 2 has 314
doc_id 3 has 2718
doc_id 4 has 42
doc_id 5 has 128
doc_id 6 has 11235
.
.
.
Probably simple but I just can't figure it out.
Do a join with two tables and add a GROUP BY clause as below:
SELECT 'doc_id 59678 has ' || count(to_doc_id) as cnt
FROM kms_doc_ref_currnt_v kv, kms_fil_nm_t kt
WHERE kt.doc_id= kv.to_doc_id
AND kv.branch_id=1
AND kv.ref_typ_cd in ('CONREF', 'KBA')
AND kv.to_doc_id=59678
GROUP BY kv.to_doc_id;
EDIT:
To get all records from kms_doc_ref_currnt_v irrespective of their reference availability in kms_fil_nm_t and kv.to_doc_id=59678, do like this:
SELECT 'doc_id 59678 has ' || count(to_doc_id) as cnt
FROM kms_doc_ref_currnt_v kv
LEFT JOIN kms_fil_nm_t kt
ON (kt.doc_id= kv.to_doc_id )
WHERE kv.branch_id=1
AND kv.ref_typ_cd in ('CONREF', 'KBA')
GROUP BY kv.to_doc_id;
to replace the hardcoding 59678, you may want to write:
SELECT 'doc_id ' || kt.doc_id || ` has ' || count(to_doc_id) as cnt
FROM kms_doc_ref_currnt_v kv
LEFT JOIN kms_fil_nm_t kt
ON (kt.doc_id= kv.to_doc_id )
WHERE kv.branch_id=1
AND kv.ref_typ_cd in ('CONREF', 'KBA')
GROUP BY kv.to_doc_id, kt.doc_id;
You need to use an outer join between the driving table that has all the doc_id values and the dependent table that may or may not have matching entries; and a group by clause to define what your aggregate function (count()) is operating against. Something like:
select 'doc_id ' || t.doc_id || ' has ' || count(*)
from kms_fil_nm_t t
left join kms_doc_ref_currnt_v v
on v.to_doc_id = t.doc_id
and v.branch_id = 1
and v.ref_typ_cd in ('CONREF', 'KBA')
group by t.doc_id;
This assumes you want to know when a doc_id isn't used, so you want entries like doc_id 1234 has 0. If you don't want to see those then you could use an inner join instead of an outer - essentially just remove the word left - but if that is the case then you don't really need to join at all, you could just do:
select 'doc_id ' || v.to_doc_id || ' has ' || count(*)
from kms_doc_ref_currnt_v v
where v.branch_id = 1
and v.ref_typ_cd in ('CONREF', 'KBA')
group by v.to_doc_id;
Unless there are to_doc_id values which are not in the other table, which would be included in the results of this query, but excluded if the tables were joined.