Consider the following setup:
CREATE TYPE list_t AS VARRAY(10) OF NUMBER(10);
/
CREATE TABLE x (
id NUMBER(10),
list list_t
);
INSERT INTO x VALUES (0, list_t());
INSERT INTO x VALUES (1, list_t(1));
INSERT INTO x VALUES (2, list_t(1, 2));
My intuition tells me that the following queries should produce the same result:
-- 1: Using 12c syntax with table constructor
SELECT x.id, x.list, y.column_value
FROM x
OUTER APPLY TABLE (x.list) y;
-- 2: Using 12c syntax with an explicit (+) operator
SELECT x.id, x.list, y.column_value
FROM x
OUTER APPLY TABLE (x.list)(+) y;
-- 3: Using 12c syntax with derived table
SELECT x.id, x.list, y.column_value
FROM x
OUTER APPLY (SELECT * FROM TABLE (x.list)) y;
-- 4: Using 11g syntax with old outer join (+)
SELECT x.id, x.list, y.column_value
FROM x, TABLE(x.list)(+) y;
-- 5: Using 12c standard syntax with LATERAL (works only on derived tables in this case)
SELECT x.id, x.list, y.column_value
FROM x
LEFT JOIN LATERAL (SELECT * FROM TABLE (x.list)) y ON 1 = 1;
However, they don't return the same result. #1's result seems wrong:
(behaves like CROSS APPLY
, seems wrong)
ID LIST COLUMN_VALUE
------------------------------------
1 TEST.LIST_T(1) 1
2 TEST.LIST_T(1, 2) 1
2 TEST.LIST_T(1, 2) 2
ID LIST COLUMN_VALUE
------------------------------------
0 TEST.LIST_T()
1 TEST.LIST_T(1) 1
2 TEST.LIST_T(1, 2) 1
2 TEST.LIST_T(1, 2) 2
To illustrate my confusion, I can add a stored function that just returns the input list:
CREATE OR REPLACE FUNCTION f (list list_t) RETURN list_t IS
BEGIN
RETURN list;
END f;
/
And then use that in the original query:
-- 1: Using 12c syntax with table constructor
SELECT x.id, x.list, y.column_value
FROM x
OUTER APPLY TABLE (f (x.list)) y;
I'm now getting the expected result with 4 rows:
ID LIST COLUMN_VALUE
------------------------------------
0 TEST.LIST_T()
1 TEST.LIST_T(1) 1
2 TEST.LIST_T(1, 2) 1
2 TEST.LIST_T(1, 2) 2
Is this a bug in Oracle 12.2.0.1.0, or is this how OUTER APPLY
and the TABLE
constructor are supposed to work?
It's a bug of the Parser, at the expansion stage. OUTER APPLY (as some other features that were added in 12.1) is apparently implemented by conversion to syntax the optimizer knew in 11g. The first query is (incorrectly) converted to INNER join, while the third is (correctly) converted to OUTER join.
-- select x.id,x.list,y.column_value from x outer apply table (list) y
select "A1"."ID_0" "ID",
"A1"."LIST_1" "LIST",
"A1"."COLUMN_VALUE_2" "COLUMN_VALUE"
from (select "A3" ."ID" "ID_0",
"A3"."LIST" "LIST_1",
"A2"."COLUMN_VALUE" "COLUMN_VALUE_2"
from "DEMO"."X" "A3",
(select value(a4) "COLUMN_VALUE"
from table("A3"."LIST") "A4") "A2"
where 1 = 1) "A1"
-- select x.id,x.list,y.column_value from x outer apply (select * from table (list)) y
select "A1"."ID_0" "ID",
"A1"."LIST_1" "LIST",
"A1"."COLUMN_VALUE_2" "COLUMN_VALUE"
from (select "A3" ."ID" "ID_0",
"A3"."LIST" "LIST_1",
"A2"."COLUMN_VALUE_0" "COLUMN_VALUE_2"
from "DEMO"."X" "A3",
lateral((select "A4"."COLUMN_VALUE_0" "COLUMN_VALUE_0"
from lateral((select "A5"."COLUMN_VALUE" "COLUMN_VALUE_0"
from (select value(a6) "COLUMN_VALUE"
from table("A3"."LIST") "A6") "A5")) "A4"
where 1 = 1))(+) "A2") "A1"