Avoiding Inner Capture in SELECT and DML Statements
Avoid inner capture of references in SELECT
, SELECT
INTO
, and DML statements by following these recommendations:
-
Specify a unique alias for each table in the statement.
-
Do not specify a table alias that is the name of a schema that owns an item referenced in the statement.
-
Qualify each column reference in the statement with the appropriate table alias.
In Example B-7, schema hr
owns tables tab1
and tab2
. Table tab1
has a column named tab2
, whose Abstract Data Type (ADT) has attribute a
. Table tab2
does not have a column named a
. Against recommendation, the query specifies alias hr
for table tab1
and references table tab2
. Therefore, in the query, the reference hr.tab2.a
resolves to table tab1
, column tab2
, attribute a
. Then the example adds column a
to table tab2
. Now the reference hr.tab2.a
in the query resolves to schema hr
, table tab2
, column a
. Column a
of table tab2
captures the reference to attribute a
in column tab2
of table tab1
.
Topics
Example B-7 Inner Capture of Attribute Reference
CREATE OR REPLACE TYPE type1 AS OBJECT (a NUMBER); / DROP TABLE tab1; CREATE TABLE tab1 (tab2 type1); INSERT INTO tab1 (tab2) VALUES (type1(10)); DROP TABLE tab2; CREATE TABLE tab2 (x NUMBER); INSERT INTO tab2 (x) VALUES (10); /* Alias tab1 with same name as schema name, a bad practice used here for illustration purpose. Note lack of alias in second SELECT statement. */ SELECT * FROM tab1 hr WHERE EXISTS (SELECT * FROM hr.tab2 WHERE x = hr.tab2.a);
Result:
TAB2(A) --------------- TYPE1(10) 1 row selected.
Add a column named a
to table tab2
(which belongs to schema hr
):
ALTER TABLE tab2 ADD (a NUMBER);
Now, when the query runs, hr.tab2.a
resolves to schema hr
, table tab2
, column a
. To avoid this inner capture, apply the recommendations to the query:
SELECT * FROM hr.tab1 p1 WHERE EXISTS (SELECT * FROM hr.tab2 p2 WHERE p2.x = p1.tab2.a);
Qualifying References to Attributes and Methods
To reference an attribute or method of a table element, you must give the table an alias and use the alias to qualify the reference to the attribute or method.
In Example B-8, table tbl1
has column col1
of data type t1
, an ADT with attribute x
. The example shows several correct and incorrect references to tbl1.col1.x
.
Example B-8 Qualifying ADT Attribute References
CREATE OR REPLACE TYPE t1 AS OBJECT (x NUMBER); / DROP TABLE tb1; CREATE TABLE tb1 (col1 t1);
The references in the following INSERT
statements do not need aliases, because they have no column lists:
BEGIN INSERT INTO tb1 VALUES ( t1(10) ); INSERT INTO tb1 VALUES ( t1(20) ); INSERT INTO tb1 VALUES ( t1(30) ); END; /
The following references to the attribute x
cause error ORA-00904:
UPDATE tb1 SET col1.x = 10 WHERE col1.x = 20; UPDATE tb1 SET tb1.col1.x = 10 WHERE tb1.col1.x = 20; UPDATE hr.tb1 SET hr.tb1.col1.x = 10 WHERE hr.tb1.col1.x = 20; DELETE FROM tb1 WHERE tb1.col1.x = 10;
The following references to the attribute x
, with table aliases, are correct:
UPDATE hr.tb1 t SET t.col1.x = 10 WHERE t.col1.x = 20; DECLARE y NUMBER; BEGIN SELECT t.col1.x INTO y FROM tb1 t WHERE t.col1.x = 30; END; / DELETE FROM tb1 t WHERE t.col1.x = 10;
Qualifying References to Row Expressions
Row expressions must resolve as references to table aliases. A row expression can appear in the SET
clause of an UPDATE
statement or be the parameter of the SQL function REF
or VALUE
.
In Example B-9, table ot1
is a standalone nested table of elements of data type t1
, an ADT with attribute x
. The example shows several correct and incorrect references to row expressions.
Example B-9 Qualifying References to Row Expressions
CREATE OR REPLACE TYPE t1 AS OBJECT (x number); / DROP TABLE ot1; CREATE TABLE ot1 OF t1; BEGIN INSERT INTO ot1 VALUES (t1(10)); INSERT INTO ot1 VALUES (20); INSERT INTO ot1 VALUES (30); END; /
The following references cause error ORA-00904:
UPDATE ot1 SET VALUE(ot1.x) = t1(20) WHERE VALUE(ot1.x) = t1(10); DELETE FROM ot1 WHERE VALUE(ot1) = (t1(10));
The following references, with table aliases, are correct:
UPDATE ot1 o SET o = (t1(20)) WHERE o.x = 10; DECLARE n_ref REF t1; BEGIN SELECT REF(o) INTO n_ref FROM ot1 o WHERE VALUE(o) = t1(30); END; / DECLARE n t1; BEGIN SELECT VALUE(o) INTO n FROM ot1 o WHERE VALUE(o) = t1(30); END; / DECLARE n NUMBER; BEGIN SELECT o.x INTO n FROM ot1 o WHERE o.x = 30; END; / DELETE FROM ot1 o WHERE VALUE(o) = (t1(20));