1

考虑以下设置:

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));

我的直觉告诉我,以下查询应该产生相同的结果:

-- 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;

但是,它们不会返回相同的结果。#1 的结果似乎是错误的:

结果 1

(表现得像CROSS APPLY,似乎错了)

ID  LIST                COLUMN_VALUE
------------------------------------
1   TEST.LIST_T(1)      1
2   TEST.LIST_T(1, 2)   1
2   TEST.LIST_T(1, 2)   2

结果 2、3、4 和 5

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

使用存储函数的替代方法

为了说明我的困惑,我可以添加一个只返回输入列表的存储函数:

CREATE OR REPLACE FUNCTION f (list list_t) RETURN list_t IS
BEGIN
  RETURN list;
END f;
/

然后在原始查询中使用它:

-- 1: Using 12c syntax with table constructor
SELECT x.id, x.list, y.column_value
FROM x
OUTER APPLY TABLE (f (x.list)) y;

我现在得到了 4 行的预期结果:

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

问题

这是 Oracle 12.2.0.1.0 中的错误,还是OUTER APPLY构造TABLE函数应该如何工作?

4

1 回答 1

1

这是解析器的错误,在扩展阶段。OUTER APPLY(作为 12.1 中添加的其他一些特性)显然是通过转换为优化器在 11g 中知道的语法来实现的。第一个查询(错误地)转换为 INNER 连接,而第三个查询(正确)转换为 OUTER 连接。

-- 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"
于 2018-01-15T12:00:13.503 回答