问题描述
@H_404_0@我看到了一些使用XMLTABLE对Oracle中的逗号分隔的字符串进行排序的示例。尽管我们永远不必通过适当的数据库设计来做到这一点,但它使我感到好奇,并且我完全不了解一件事:
@H_404_0@为什么允许交叉连接来自另一个表的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
@H_404_0@结果:
+-----------+-----------+ | CSV | SORTED | +-----------+-----------+ | b,d | a,b,d | | w,e | e,w | +-----------+-----------+@H_404_0@我正在传递
t.csv
,我认为交叉连接右侧不应该访问该信息。
@H_404_0@有人可以解释这里发生了什么吗?我开始认为Oracle出于某种原因弄混了它,从而违反了sql标准。我说的对吗?
@H_404_0@如果您可以在这里解释Oracle的功能,那肯定也可以解释为什么添加此功能
where sorted <> 'x'
@H_404_0@导致意外结果。出乎我意料的是:-)
@H_404_0@带有WHERE
子句的结果:
+-----------+--------+ | CSV | SORTED | +-----------+--------+ | b,d | | w,e | a,d | +-----------+--------+@H_404_0@演示:https://dbfiddle.uk/?rdbms=oracle_18&fiddle=a9497bec423a3facbd29b49b3a40a350
解决方法
您的“为什么”问题可能很难回答;可能是因为这是Oracle使用旧的逗号联接语法然后在以后添加ANSI语法,然后在Oracle 12c中添加CROSS APPLY
来执行相关查询的方法,但是要找到文档来支持这一点将是一个挑战。
但是,如果您可以在应用CROSS JOIN
过滤器子句之前强制对相关的ROWNUM
进行评估(通过执行无用的特定于行的操作,例如生成WHERE
伪列),那么您就可以使用该查询了:
WITH t ( csv ) AS (
select 'b,a,d' from dual union all
select 'w,o,r,s,e' from dual union all
select 'w,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,d | a,b,d w,e | e,w w,r | e,w
db 提琴here