The new PL/SQL procedure DBMS_UTILITY.expand_sql_text can be used to generate a single SQL statement, referencing only tables, from a query involving one or more views. On the surface of it, this sounded great for getting a single view (in the non Oracle sense) of the tables involved in a query. The signature of DBMS_UTILITY.expand_sql_text is
PROCEDURE EXPAND_SQL_TEXT Argument Name Type In/Out Default? ------------------------------ ----------------------- ------ -------- INPUT_SQL_TEXT CLOB IN OUTPUT_SQL_TEXT CLOB OUT
Although a single query is produced by DBMS_UTILITY.expand_sql_text, it may take a bit of reformatting and manual simplification to get your head round. By way of example, consider the simple query below involving three tables, and one view.
Example table and view set up script
CREATE TABLE vt1 ( id NUMBER NOT NULL, payload VARCHAR2(30) NOT NULL, CONSTRAINT vt1_pk PRIMARY KEY (id) ); CREATE TABLE vt2 ( id NUMBER NOT NULL, payload VARCHAR2(30) NOT NULL, CONSTRAINT vt2_pk PRIMARY KEY (id) ); CREATE TABLE vt3 ( id NUMBER NOT NULL, payload VARCHAR2(30) NOT NULL, CONSTRAINT vt3_pk PRIMARY KEY (id) ); CREATE VIEW vt1_and_vt2_join AS SELECT id, a.payload a_payload, b.payload b_payload FROM vt1 a JOIN vt2 b USING (id)
The join of interest
SELECT * FROM vt3 JOIN vt1_and_vt2_join USING (id);
Using DBMS_UTILITY.expand_sql_text to obtain the query "with the identical meaning" to the above join which references only tables
DECLARE lc_query_in CLOB; lc_query_out CLOB; BEGIN lc_query_in := 'SELECT * FROM vt3 JOIN vt1_and_vt2_join USING (id)'; DBMS_UTILITY.expand_sql_text(lc_query_in, lc_query_out); DBMS_OUTPUT.put_line(lc_query_out); END; /
The raw output produced by DBMS_UTILITY.expand_sql_text for our example is
SELECT "A1"."ID_0" "ID","A1"."PAYLOAD_1" "PAYLOAD","A1"."A_PAYLOAD_2" "A_PAYLOAD","A1"."B_PAYLOAD_3" "B_PAYLOAD" FROM (SELECT "A2"."ID" "ID_0","A3"."PAYLOAD" "PAYLOAD_1","A2"."A_PAYLOAD" "A_PAYLOAD_2","A2"."B_PAYLOAD" "B_PAYLOAD_3" FROM "RIK"."VT3" "A3", (SELECT "A4"."ID_0" "ID","A4"."QCSJ_C000000000600000_1" "A_PAYLOAD","A4"."QCSJ_C000000000600001_2" "B_PAYLOAD" FROM (SELECT "A5"."ID" "ID_0","A6"."PAYLOAD" "QCSJ_C000000000600000_1","A5"."PAYLOAD" "QCSJ_C000000000600001_2" FROM RIK."VT1" "A6",RIK."VT2" "A5" WHERE "A6"."ID"="A5"."ID") "A4") "A2" WHERE "A3"."ID"="A2"."ID") "A1"
As the above is a bit unreadable, removing the quotes, putting owner, table, field and alias names in lower case, and formatting the output a bit, yields the following query
SELECT a1.id_0 id, a1.payload_1 payload, a1.a_payload_2 a_payload, a1.b_payload_3 b_payload FROM (SELECT a2.id id_0, a3.payload payload_1, a2.a_payload a_payload_2, a2.b_payload b_payload_3 FROM rik.vt3 a3, (SELECT a4.id_0 id, a4.qcsj_c000000000600000_1 a_payload, a4.qcsj_c000000000600001_2 b_payload FROM (SELECT a5.id id_0, a6.payload qcsj_c000000000600000_1, a5.payload qcsj_c000000000600001_2 FROM rik.vt1 a6, rik.vt2 a5 WHERE a6.id = a5.id ) a4 ) a2 WHERE a3.id = a2.id ) a1;
From the above one can see the DBMS_UTILITY.expand_sql_text approach to obtain an output query for a given input query is
So each view in turn in the DBMS_UTILITY.expand_sql_text input query results in a "join" subquery, and a wrapping "presentation" subquery. Views joined in either the input query or in another view within the input query also result in both a "join" subquery and "presentation" subquery.
It strikes me that it wouldn't be that hard to merge each join and presentation subquery pair into a single subquery. Given that this has not been done, I'm sure there must be a good reason why not, but, for now at least, I can't think of it.