I am trying to write a statistic about the data warehouse tables that are used.
Therefor I should make a query to bring the used tables.
I have a list of table n
Here is the solution that I searched for:
WITH dwtables(dwtable) AS (
SELECT 'DWA' FROM dual UNION ALL
SELECT 'DWB' FROM dual UNION ALL
SELECT 'DWC' FROM dual
)--> Tabelle mit einem Spalte (Liste)
SELECT title,
(SELECT LISTAGG (dwtable, ', ' ) WITHIN GROUP (ORDER BY dwtable)
FROM dwtables
WHERE REGEXP_LIKE (r.querytext, '(^|\s)'||dwtables.dwtable||'(\s|$)', 'i')) AS dwtables
FROM Reports r;
Simple approach to extract the table names from a list of SQL queries
Setup Let's suppose this is your query list:
select * from a where id = 1;
select * from v;
with my_id as (select id from b)
select /*+ PARALLEL(4) */ * from a where id in (select id from my_id);
To cover also the view access, here is the table definition:
create table a (id number);
create index a_idx on a(id);
create table b (id number);
create table c (id number);
create table d (id number);
create view v as
select c.id from c join d on c.id = d.id;
So there are tables a, b, c and d
and v
is view on c and d
*As a result you want so see a list of tables a, b, c and d
, even that in your query list only the tables a, b
are directly referenced.
Solution
In the first step convert your query list in a list of EXPLAIN PLAN
statements. You may find it practicable to use some sort of scripting if the list is of non-trivial length:
EXPLAIN PLAN SET STATEMENT_ID = 'q1' into plan_table FOR select * from a where id = 1;
EXPLAIN PLAN SET STATEMENT_ID = 'q2' into plan_table FOR select * from v;
EXPLAIN PLAN SET STATEMENT_ID = 'q3' into plan_table FOR with my_id as (select id from b)
select /*+ PARALLEL(4) */ * from a where id in (select id from my_id);
Through execution the EXPLAIN PLAN
statements the plan_table
is filled with the execution plans and accessed objects are for each operation are stored in columns OBJECT_OWNER, OBJECT_NAME
.
The first naive query returns this list:
select distinct OBJECT_OWNER, OBJECT_NAME
from plan_table
where statement_id in ('q1','q2','q3') and OBJECT_NAME is not NULL
order by 1,2;
OBJECT_OWNER OBJECT_NAME
------------ -----------
DWH A_IDX
DWH B
DWH C
DWH D
SYS :TQ10000
SYS :TQ10001
SYS :TQ10002
Two things must be fixed.
First the row sources for parallel execution must be ignored (e.g. :TQ10000
) as they are not a real tables.
Second the index names (e.g. A_IDX
) must be mapped to table_names using the dictionary view DBA_INDEXES
.
Note that you need not take a special care for views, as they are parsed automatically to the source tables. The same is true for the subquery factoring (with
clause).
The query approaching both topics is shown below:
select distinct OBJECT_OWNER,
/* map index name to table name */
case when p.OPERATION = 'INDEX' then i.TABLE_NAME else p.OBJECT_NAME end as TABLE_NAME
from plan_table p
left outer join dba_indexes i on p.OBJECT_OWNER = i.OWNER and p.OBJECT_NAME = i.INDEX_NAME
where statement_id in ('q1','q2','q3') and OBJECT_NAME is not NULL
and p.OBJECT_NAME not like ':%' /* suppress parallel row sources */
order by 1,2;
OBJECT_OWNER TABLE_NAME
------------ ----------
DWH A
DWH B
DWH C
DWH D
Final note, this approach work only if all queries and views are syntactically valid and you have a user with enough rights to explain plan for all the queries from your list.