-1

假设我想动态定义一些表格数据以在查询中使用,而不创建物理表:

+------------+------------+
|COLUMN_VALUE|COLUMN_VALUE|
+------------+------------+
|1           |a           |
|2           |b           |
|5           |e           |
|4           |d           |
|3           |c           |
+------------+------------+

(注意顺序)

我怎样才能尽可能简洁明了地做到这一点?

我能想出什么(不那么漂亮):

with
    x as (
        select
            column_value
        from
            table (sys.odcinumberlist(1, 2, 5, 4, 3))),

    y as (
        select
            column_value
        from
            table (sys.odcivarchar2list('a', 'b', 'e', 'd', 'c')))
select
    x.column_value,
    y.column_value
from
    x
inner join y on x.rownum = y.rownum;

但是,这不起作用,因为它与ORA-01747: invalid user.table.column, table.column, or column specification. 显然,rownum使用内置table()函数时不支持伪列。

在 CTE 中使用row_number() over (order by column_value asc)似乎很有效,但会强制对列值进行排序。这是不可取的,因为值应该按照它们在表函数中定义的顺序出现。

4

2 回答 2

0

Oracle Database Ideas 论坛上有一个社区建议向标量集合添加ordinality列,但我认为这不太可能在我们的有生之年实现。还有一个语法建议,允许使用values类似于Postgres Values lists的子句动态声明集合,尽管我现在找不到它。

目前您的选择是:

  1. 使用多个select from dual查询union all来明确定义所有必需的行。

  2. 定义自定义对象和集合类型以便使用table()和对象声明性语法。

我同意两者都不理想。

方法示例select from dual

with test_data (id, somevalue) as
     (
       select 1, 'a' from dual union all
       select 2, 'b' from dual union all
       select 5, 'e' from dual union all
       select 4, 'd' from dual union all
       select 3, 'c' from dual
     )
select id, somevalue
from   test_data

关于生成的行编号,您可以使用

row_number() over(order by null)

从技术上讲,这不能保证保留顺序,但从 Oracle 21c 开始,它似乎在实践中这样做了。

select column_value
     , row_number() over (order by null) as rn
from   table (sys.odcivarchar2list('a', 'b', 'e', 'd', 'c'));

COLUMN_VALUE         RN
------------ ----------
a                     1
b                     2
e                     3
d                     4
c                     5

关于您的 ORA-01747 错误x.rownum,这不是因为对table()运算符的任何限制。这样的构造有两个问题(查询的简化版本):

with demo as
     ( select dummy from dual )
select x.rownum from demo x
  1. CTEdemo没有名为“rownum”的列。它只有一列 ( dummy),因此这是您可以参考的唯一 x.column。
  2. 即使您添加rownum到查询中,也不能将其称为列,x.rownum因为它是关键字。解决方案是在 CTE 中将其别名为“seq”或“rn”,然后可以参考:
with demo as
     ( select dummy, rownum as rn from dual )
select x.rn from demo x
于 2021-12-31T19:38:45.593 回答
-1

解决方案是别名 rownum 列(也整理了查询):

select
    x.column_value,
    y.column_value
from
    (select column_value, rownum as rn from table (sys.odcinumberlist(1, 2, 5, 4, 3))) x
        inner join
        (select column_value, rownum as rn from table (sys.odcivarchar2list('a', 'b', 'e', 'd', 'c'))) y on x.rn = y.rn;
于 2021-12-31T14:12:23.337 回答