【发布时间】:2013-06-11 09:17:13
【问题描述】:
请帮助我确认下面解释的行为是错误,或者清楚地解释为什么它是正确的。 我很可能误解了一些概念,但现在对我来说它看起来像一个错误。
下面的所有示例都尽可能简化以展示问题的核心。实际情况非常复杂,因此只能接受与查询构造原理相关的一般性答案和变通方法。
欢迎您在 cmets 中提出澄清问题,我会尽力回答。
感谢您的关注。 :)
问题
为什么在上一个示例(示例 5)(select count(1) ... 子查询中的 collection 实例从第一行映射到表的所有行,而预期结果是将每个 collection 实例映射到它自己的行?
同时collections中使用的cardinality(...)表达式选择正确。
如果以这种方式构造用于查询的from 或where 部分的集合,则存在相同的情况(示例中未涵盖)。
测试架构设置
create or replace type TabType0 as table of varchar2(100)
/
create table Table0( tab_str_field varchar2(100), tab_field TabType0)
nested table tab_field store as tab_field_table
/
insert into table0 (tab_str_field, tab_field) values (
'A',
cast(multiset(
select 'A' from dual union all
select 'B' from dual union all
select 'C' from dual
) as TabType0)
)
/
insert into table0 (tab_str_field, tab_field) values (
'B',
cast(multiset(
select 'B' from dual union all
select 'C' from dual
) as TabType0)
)
/
insert into table0 (tab_str_field, tab_field) values (
'C',
cast(multiset(
select 'A' from dual union all
select 'B' from dual union all
select 'C' from dual union all
select 'D' from dual
) as TabType0)
)
/
insert into table0 (tab_str_field, tab_field) values (
'D',
cast(multiset(
select 'A' from dual
) as TabType0)
)
/
select 'Initial table data' caption from dual
/
select * from table0
/
表格数据:
| TAB_STR_FIELD | TAB_FIELD |
-----------------------------
| A | A,B,C |
| B | B,C |
| C | A,B,C,D |
| D | A |
示例
示例 1 (SQLFiddle) - 使用嵌套表字段 - OK
select 'Work with nested table - OK' caption from dual
/
select
tab_field tab_field,
-- cardinality
cardinality(tab_field) tab_cardinality,
-- select from table field of current row
(select count(1) from table(tab_field)) tab_count,
-- select from field of current row while joining
-- with another field of same row
( select column_value from table(tab_field)
where column_value = tab_str_field
) same_value
from table0
/
结果:
| TAB_FIELD | TAB_CARDINALITY | TAB_COUNT | SAME_VALUE |
--------------------------------------------------------
| A,B,C | 3 | 3 | A |
| B,C | 2 | 2 | B |
| A,B,C,D | 4 | 4 | C |
| A | 1 | 1 | (null) |
示例 2 (SQLFiddle) - 单独使用构造的源数据 - OK
select 'Work with constructed source data alone - OK' caption from dual
/
with table_data_from_set as (
select
'A' tab_str_field,
cast(multiset(
select 'A' from dual union all
select 'B' from dual union all
select 'C' from dual
) as TabType0) tab_field
from dual union all
select
'B' tab_str_field,
cast(multiset(
select 'B' from dual union all
select 'C' from dual
) as TabType0) tab_field
from dual union all
select
'C' tab_str_field,
cast(multiset(
select 'A' from dual union all
select 'B' from dual union all
select 'C' from dual union all
select 'D' from dual
) as TabType0) tab_field
from dual union all
select
'D' tab_str_field,
cast(multiset(
select 'A' from dual
) as TabType0) tab_field
from dual
)
select
tab_field tab_field,
-- cardinality
cardinality(tab_field) tab_cardinality,
-- select from table field of current row
(select count(1) from table(tab_field)) tab_count,
-- select from field of current row while joining
-- with another field of same row
( select column_value from table(tab_field)
where column_value = tab_str_field
) same_value
from table_data_from_set
/
结果:
| TAB_FIELD | TAB_CARDINALITY | TAB_COUNT | SAME_VALUE |
--------------------------------------------------------
| A,B,C | 3 | 3 | A |
| B,C | 2 | 2 | B |
| A,B,C,D | 4 | 4 | C |
| A | 1 | 1 | (null) |
示例 3 (SQLFiddle) - 使用在 WITH 中构造的多重集连接表 - OK
select 'Join table with multisets constructed in WITH - OK' caption from dual
/
with table_data_from_set as (
select
'A' tab_str_field,
cast(multiset(
select 'A' from dual union all
select 'B' from dual union all
select 'C' from dual
) as TabType0) tab_field
from dual union all
select
'B' tab_str_field,
cast(multiset(
select 'B' from dual union all
select 'C' from dual
) as TabType0) tab_field
from dual union all
select
'C' tab_str_field,
cast(multiset(
select 'A' from dual union all
select 'B' from dual union all
select 'C' from dual union all
select 'D' from dual
) as TabType0) tab_field
from dual union all
select
'D' tab_str_field,
cast(multiset(
select 'A' from dual
) as TabType0) tab_field
from dual
)
select
table0.tab_field table0_tab_field,
table_data_from_set.tab_field set_tab_field,
-- cardinality
cardinality(table0.tab_field) table0_tab_cardinality,
cardinality(table_data_from_set.tab_field) set_tab_cardinality,
-- select from table field of current row
(select count(1) from table(table_data_from_set.tab_field)) set_tab_count,
-- select from field of current row while joining
-- with another field of same row
( select column_value from table(table_data_from_set.tab_field)
where column_value = table0.tab_str_field
) same_value
from
table0,
table_data_from_set
where
table_data_from_set.tab_str_field = table0.tab_str_field
/
结果:
| TABLE0_TAB_FIELD | SET_TAB_FIELD | TABLE0_TAB_CARDINALITY | SET_TAB_CARDINALITY | SET_TAB_COUNT | SAME_VALUE |
----------------------------------------------------------------------------------------------------------------
| A,B,C | A,B,C | 3 | 3 | 3 | A |
| B,C | B,C | 2 | 2 | 2 | B |
| A,B,C,D | A,B,C,D | 4 | 4 | 4 | C |
| A | A | 1 | 1 | 1 | (null) |
示例 4 (SQLFiddle) - 使用 WITH + 子查询构造的多集连接表 - OK
select 'Join table with multisets constructed in WITH and subquery - OK' caption from dual
/
with table_data_from_set as (
select
'A' tab_str_field,
cast(multiset(
select 'A' from dual union all
select 'B' from dual union all
select 'C' from dual
) as TabType0) tab_field
from dual union all
select
'B' tab_str_field,
cast(multiset(
select 'B' from dual union all
select 'C' from dual
) as TabType0) tab_field
from dual union all
select
'C' tab_str_field,
cast(multiset(
select 'A' from dual union all
select 'B' from dual union all
select 'C' from dual union all
select 'D' from dual
) as TabType0) tab_field
from dual union all
select
'D' tab_str_field,
cast(multiset(
select 'A' from dual
) as TabType0) tab_field
from dual
)
select
table0_tab_field table0_tab_field,
set_tab_field set_tab_field,
-- cardinality
cardinality(table0_tab_field) table0_tab_cardinality,
cardinality(set_tab_field) set_tab_cardinality,
-- select from table field of current row
(select count(1) from table(set_tab_field)) set_tab_count,
-- select from field of current row while joining
-- with another field of same row
( select column_value from table(set_tab_field)
where column_value = table0_tab_str_field
) same_value
from (
select
table0.tab_str_field table0_tab_str_field,
table0.tab_field table0_tab_field,
table_data_from_set.tab_str_field set_tab_str_field,
table_data_from_set.tab_field set_tab_field
from
table0,
table_data_from_set
where
table_data_from_set.tab_str_field = table0.tab_str_field
)
/
结果:
| TABLE0_TAB_FIELD | SET_TAB_FIELD | TABLE0_TAB_CARDINALITY | SET_TAB_CARDINALITY | SET_TAB_COUNT | SAME_VALUE |
----------------------------------------------------------------------------------------------------------------
| A,B,C | A,B,C | 3 | 3 | 3 | A |
| B,C | B,C | 2 | 2 | 2 | B |
| A,B,C,D | A,B,C,D | 4 | 4 | 4 | C |
| A | A | 1 | 1 | 1 | (null) |
示例 5 (SQLFiddle) - 使用动态构建的多集连接表 - FAILED
select 'Join table with multisets constructed on the fly - FAIL (set_tab_count wrong)' caption from dual
/
with string_set as (
select 'A' str_field from dual union all
select 'B' str_field from dual union all
select 'C' str_field from dual union all
select 'D' str_field from dual union all
select 'E' str_field from dual
)
select
table0_tab_field table0_tab_field,
set_tab_field set_tab_field,
-- cardinality
cardinality(table0_tab_field) table0_tab_cardinality,
cardinality(set_tab_field) set_tab_cardinality,
-- select from table field of current row
(select count(1) from table(set_tab_field)) set_tab_count,
-- select from field of current row while joining
-- with another field of same row
( select column_value from table(set_tab_field)
where column_value = table0_tab_str_field
) same_value
from (
select
table0.tab_str_field table0_tab_str_field,
table0.tab_field table0_tab_field,
(
cast(multiset(
select
string_set.str_field
from
string_set,
table(table0.tab_field) tab_table
where
string_set.str_field = tab_table.column_value
) as TabType0)
) set_tab_field
from
table0
)
/
结果(set_tab_count 列中的所有值都相同 - 错误!):
| TABLE0_TAB_FIELD | SET_TAB_FIELD | TABLE0_TAB_CARDINALITY | SET_TAB_CARDINALITY | SET_TAB_COUNT | SAME_VALUE |
----------------------------------------------------------------------------------------------------------------
| A,B,C | A,B,C | 3 | 3 | 3 | A |
| B,C | B,C | 2 | 2 | 3 | B |
| A,B,C,D | A,B,C,D | 4 | 4 | 3 | C |
| A | A | 1 | 1 | 3 | (null) |
Oracle 版本信息
实例 1
BANNER
--------------------------------------------------------------------------------
Oracle Database 11g Enterprise Edition Release 11.2.0.3.0 - 64bit Production
PL/SQL Release 11.2.0.3.0 - Production
CORE 11.2.0.3.0 Production
TNS for IBM/AIX RISC System/6000: Version 11.2.0.3.0 - Production
NLSRTL Version 11.2.0.3.0 - Production
实例 2
BANNER
--------------------------------------------------------------------------------
Oracle Database 11g Express Edition Release 11.2.0.2.0 - Production
PL/SQL Release 11.2.0.2.0 - Production
CORE 11.2.0.2.0 Production
TNS for 32-bit Windows: Version 11.2.0.2.0 - Production
NLSRTL Version 11.2.0.2.0 - Production
SQLFiddle 将所有查询放在一起。
【问题讨论】:
-
这太令人困惑了。你没有很好地阐明你想要做什么,预期的结果是什么,以及到底出了什么问题。我所知道的是,您在上次测试中对
set_tab_count的结果不是您所期望的。我不知道这个值应该代表什么,而且我没有通读所有这些代码。我很欣赏这可能是您可以简化可重现的测试用例的最简单方法,但如果是这种情况,您需要对您的代码进行一些解释,因为我们不会对所有内容进行挑剔。 -
@DavidMarx 你需要什么样的解释才能理解以上所有内容?前 4 个示例演示了在连接中使用集合的不同方法的相同结果。但是第五个结果打破了前 4 个例子中可以看到的所有逻辑。我只是想了解示例 5 中的逻辑或得到合理的解释为什么它是一个错误。
-
在 OTN 论坛 (forums.oracle.com/thread/2550938) 上回答我的问题时建议了另外 2 个解决方法,但比@jonearles 提供的更具体
标签: sql oracle collections oracle11g multiset