如何即时创建带有手动数据的 table

How to create a table with manual data on the fly

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

+------------+------------+
|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。显然,使用内置 table() 函数时 rownum 伪列不受支持。

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

解决方案是为 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;

Oracle 数据库创意论坛上有一个社区建议 add an ordinality pseudocolumn to scalar collections, but I'd say it's unlikely to be implemented in our lifetimes. There is also a suggestion for syntax to allow sets to be declared on the fly using a values clause similar to 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

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

with demo as
     ( select dummy from dual )
select x.rownum from demo x
  1. CTE demo 没有名为 '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