为什么我可以交叉连接 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
我看到了使用 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