2

以下で説明する動作がバグであることを確認するのを手伝ってください。または、それが正しい理由を明確に説明してください。いくつかの概念を誤解している可能性が高いですが、今ではバグのように見えます。

以下のすべての例は、問題の核心を示すために可能な限り単純化されています。実際の状況は非常に複雑であるため、一般的な回答とクエリ構築の原則に関連する回避策のみが受け入れられます。
コメントで明確な質問をすることを歓迎します。私はそれらに答えるために最善を尽くします.
清聴ありがとうございました。:)

質問

最後の例 (例 5)では、最初の行からのサブクエリのcollectionインスタンスが (select count(1) ...テーブルのすべての行にマップされているのに、期待される結果は各collectionインスタンスを独自の行にマップすることになるのはなぜですか?
同時に、適切に選択された表現collectionsで使用されます。クエリ内またはクエリの一部で 使用されるコレクションがこのように構築されている場合、同じ状況 (例ではカバーされていません) が存在します。cardinality(...)
fromwhere

テストスキーマの設定

( SQLフィドル)

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 ) - オンザフライで構築されたマルチセットを含む結合テーブル -失敗

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 。

4

1 に答える 1

2

バグです。/*+ NO_MERGE */最後の例の 2 番目のインライン ビューにヒントを追加すると、期待どおりの結果が得られます。例については、この SQL Fiddleを参照してください。クエリに関係なく、そのヒントによって結果が変わることはありません。いくつかの列を削除したりROWNUM、途中で使用されていないものを追加したりするなど、正しい結果を生成するために行うことができる、一見無関係に見える変更が他にもいくつかあります。

オラクルはクエリを最適化するために書き直していますが、何か間違っています。クエリをトレースすることで、さらに多くの情報を取得できる可能性がありますが、問題を本当に解決できるとは思えません。現時点では問題を回避し、サービス リクエストを Oracle に送信して、バグを作成し、最終的に修正できるようにします。

于 2013-06-14T23:02:58.500 に答える