为什么我可以交叉连接 XMLTABLE?为什么我不必交叉申请?

Why can I cross join XMLTABLE? Why don't I have to cross apply?

我看到了使用 XMLTABLE 在 Oracle 中对逗号分隔的字符串进行排序的示例。虽然我们永远不必通过适当的数据库设计来做到这一点,但这让我感到好奇,有一件事我根本不明白:

为什么允许我交叉连接来自其他 table 的 XMLTABLE 引用列?我希望必须应用横向连接 (CROSS APPLY),但这似乎不需要。此查询有效:

select *
from 
(
  select 'b,a,d' as csv from dual
  union all
  select 'w,o,r,s,e' as csv from dual
) t
cross join xmltable
(
  'if (contains($csv, ",")) then string-join(for $str in ora:tokenize($csv, ",") order by $str return $str, ",") else $csv'
   passing t.csv as "csv"
   columns sorted varchar2(4000) path '.'
) x

结果:

+-----------+-----------+
|    CSV    |  SORTED   |
+-----------+-----------+
| b,a,d     | a,b,d     |
| w,o,r,s,e | e,o,r,s,w |
+-----------+-----------+

我正在传递 t.csv,我认为它不应该在交叉连接的右侧访问。

谁能解释一下这里发生了什么?我开始认为 Oracle 出于某种原因在这里蒙混过关,从而违反了 SQL 标准。我说得对吗?

如果你能解释 Oracle 在这里做了什么,这当然也能解释为什么要添加这个

where sorted <> 'x'

导致意想不到的结果。出乎我意料的是:-)

带有 WHERE 子句的结果:

+-----------+--------+
|    CSV    | SORTED |
+-----------+--------+
| b,a,d     | a,b,d  |
| w,o,r,s,e | a,b,d  |
+-----------+--------+

演示:https://dbfiddle.uk/?rdbms=oracle_18&fiddle=a9497bec423a3facbd29b49b3a40a350

您的“为什么”问题可能很难回答;这可能是因为这就是 Oracle 使用其遗留 comma-join 语法执行相关查询的方式,然后稍后添加 ANSI 语法,然后在 Oracle 12c 中添加 CROSS APPLY 但是找到文档来支持这一点将具有挑战性。

但是,如果您可以在应用 [=14] 之前强制计算相关 CROSS JOIN(通过执行无用的行特定操作,例如生成 ROWNUM pseudo-column) =] filter 子句然后你可以让查询工作:

WITH t ( csv ) AS (
  select 'b,a,d'       from dual union all
  select 'w,o,r,s,e'   from dual union all
  select 'w,o,r,s,e,r' from dual
)
SELECT csv,
       sorted
FROM   (
  select ROWNUM as id,
         t.csv,
         s.sorted
  from   t
         CROSS JOIN xmltable (
           'if (contains($csv, ",")) then string-join(for $str in ora:tokenize($csv, ",") order by $str return $str, ",") else $csv'
           passing t.csv as "csv"
           columns sorted varchar2(4000) path '.'
         ) s
)
WHERE  sorted <> 'x';

输出:

CSV         | SORTED     
:---------- | :----------
b,a,d       | a,b,d      
w,o,r,s,e   | e,o,r,s,w  
w,o,r,s,e,r | e,o,r,r,s,w

db<>fiddle here