3

というテーブルに乱雑なデータがありますAVAILABLE_TEMPLATES。簡単な例を次に示します。

TEMPLATE_GROUP TEMPLATE_NAME LOCALE
-------------- ------------- ------
RO              LTRU          fi_FI  
RO              LTRU          se_SE  
RO              LTRU          en_US  
BL              V1PRO         se_SE  
BL              V1PRO         en_US  

というロケールを含む別のテーブルがありますSYSTEM_LOCALES

SYS_LOCALE
------
lv_LV  
fi_FI  
sv_SE  
en_US

これら 2 つのテーブルを結合して取得しようとしているデータには、テーブル内の行とテーブルからの個別の / のデカルト積が含まれている必要がSYS_LOCALEありTEMPLATE_GROUPます。TEMPLATE_NAMEAVAILABLE_TEMPLATES

デフォルトのロケールはfi_FI. のそれぞれについてTEMPLATE_NAMETEMPLATE_GROUP一致するロケールが利用可能かどうかを確認したいと思います。利用可能な場合は、として返されUSE_LOCALEます。fi_FI一致するロケールが見つからない場合は、システムのデフォルト ロケールを返したいと思いTEMPLATE_NAMEます。TEMPLATE_GROUPUSE_LOCALE

2 つのテーブルを結合すると、次のように返されます。

TEMPLATE_GROUP TEMPLATE_NAME SYS_LOCALE  USE_LOCALE
-----------    ------------- ------      ----------
RO             LTRU          lv_LV       fi_FI      --There's a fi_FI locale but no lv_LV 
RO             LTRU          fi_FI       fi_FI    
RO             LTRU          se_SE       se_SE    
RO             LTRU          en_US       en_US    
BL             V1PRO         lv_LV       NULL       --There's no lv_LV or a fi_FI locale 
BL             V1PRO         fi_FI       NULL       --There's no fi_FI locale
BL             V1PRO         se_SE       se_SE    
BL             V1PRO         en_US       en_US    

私はこれを理解することができず、かなり迷っていました。再帰で行う必要がありますか?ありがとう

4

5 に答える 5

5

テーブルを複数回読み取らずにこの操作を実行できる唯一の構造は、パーティション化された外部結合です。

データセットの例を次に示します。

SQL> create table available_templates (template_group,template_name,locale)
  2  as
  3  select 'RO', 'LTRU', 'fi_FI' from dual union all
  4  select 'RO', 'LTRU', 'se_SE' from dual union all
  5  select 'RO', 'LTRU', 'en_US' from dual union all
  6  select 'BL', 'V1PRO', 'se_SE' from dual union all
  7  select 'BL', 'V1PRO', 'en_US' from dual
  8  /

Table created.

SQL> create table system_locales (sys_locale)
  2  as
  3  select 'lv_LV' from dual union all
  4  select 'fi_FI' from dual union all
  5  select 'se_SE' from dual union all
  6  select 'en_US' from dual
  7  /

Table created.

分割された外部結合:

SQL> select at.template_group
  2       , at.template_name
  3       , sl.sys_locale
  4       , nvl
  5         ( at.locale
  6         , max(decode(at.locale,'fi_FI',at.locale)) over (partition by at.template_group, at.template_name)
  7         ) use_locale
  8    from system_locales sl
  9         left outer join available_templates at
 10           partition by (at.template_group,at.template_name)
 11           on (at.locale = sl.sys_locale)
 12  /

TEMPLATE_GROUP TEMPLATE_NAME SYS_LOCALE USE_LOCALE
-------------- ------------- ---------- ----------
BL             V1PRO         en_US      en_US
BL             V1PRO         fi_FI
BL             V1PRO         lv_LV
BL             V1PRO         se_SE      se_SE
RO             LTRU          en_US      en_US
RO             LTRU          fi_FI      fi_FI
RO             LTRU          lv_LV      fi_FI
RO             LTRU          se_SE      se_SE

8 rows selected.

以下は、テーブルが 1 回だけスキャンされたことの証拠です。

    SQL> select * from table(dbms_xplan.display_cursor(null,null,'allstats last'))
      2  /

    PLAN_TABLE_OUTPUT
    ---------------------------------------------------------------------------------------------------------------------------------------
    SQL_ID  57br33gc6n1sc, child number 0
    -------------------------------------
    select at.template_group      , at.template_name      , sl.sys_locale
       , nvl        ( at.locale        ,
    max(decode(at.locale,'fi_FI',at.locale)) over (partition by
    at.template_group, at.template_name)        ) use_locale   from
    system_locales sl        left outer join available_templates at
     partition by (at.template_group,at.template_name)          on
    (at.locale = sl.sys_locale)

    Plan hash value: 921719364

-----------------------------------------------------------------------------------------------------------------------------------------
| Id  | Operation                    | Name                | Starts | E-Rows | A-Rows |   A-Time   | Buffers |  OMem |  1Mem | Used-Mem |
-----------------------------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT             |                     |      1 |        |      8 |00:00:00.01 |       6 |       |       |          |
|   1 |  WINDOW BUFFER               |                     |      1 |      1 |      8 |00:00:00.01 |       6 |  2048 |  2048 | 2048  (0)|
|   2 |   VIEW                       |                     |      1 |      1 |      8 |00:00:00.01 |       6 |       |       |          |
|   3 |    MERGE JOIN PARTITION OUTER|                     |      1 |      1 |      8 |00:00:00.01 |       6 |       |       |          |
|   4 |     SORT JOIN                |                     |      3 |      4 |      9 |00:00:00.01 |       3 |  2048 |  2048 | 2048  (0)|
|   5 |      TABLE ACCESS FULL       | SYSTEM_LOCALES      |      1 |      4 |      4 |00:00:00.01 |       3 |       |       |          |
|*  6 |     SORT PARTITION JOIN      |                     |      9 |      5 |      5 |00:00:00.01 |       3 |  2048 |  2048 | 2048  (0)|
|   7 |      TABLE ACCESS FULL       | AVAILABLE_TEMPLATES |      1 |      5 |      5 |00:00:00.01 |       3 |       |       |          |
-----------------------------------------------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   6 - access("AT"."LOCALE"="SL"."SYS_LOCALE")
       filter("AT"."LOCALE"="SL"."SYS_LOCALE")

Note
-----
   - dynamic sampling used for this statement (level=2)


35 rows selected.

よろしく、
ロブ。

于 2013-03-04T14:16:50.253 に答える
2

次のようなことができます:

select t_base.template_group, t_base.template_name, l.sys_locale, 
      nvl( t.locale, default_locale)  use_locale
  from system_locales l
       cross join (select t.template_group, t.template_name, 
                          max(case t.locale when 'fi_FI' then  t.locale end) default_locale
                     from available_templates t
                    group by t.template_group, t.template_name) t_base
       left outer join available_templates t
               on t.template_group = t_base.template_group
              and t.template_name = t_base.template_name
              and t.locale = l.sys_locale
 order by 1, 2
于 2013-03-04T14:03:52.780 に答える
1

試す:

with templates as 
(select template_group, template_name, max(case locale when 'fi_FI' then locale end) available_default
 from available_templates
 group by template_group, template_name),
template_combinations as
(select t.*, s.sys_locale
 from templates t
 cross join sys_locale s)
select c.template_group, c.template_name, c.sys_locale, coalesce(a.locale, c.available_default) use_locale
from template_combinations c
left join available_templates a 
on c.template_group = a.template_group and c.template_name = a.template_name and c.sys_locale = a.locale

提供された情報から、データベースが不適切に正規化されているようです。少なくとも、template_group と template_name の組み合わせ用に追加のテーブルが必要です。

于 2013-03-04T14:03:16.820 に答える
1

このようなもの?

これは、ロケールとすべてのグループ/名前の星座のデカルト積を作成します。次に、グループ/名前/ロケールごとに行を返します。

CASE ステートメントは次を返します。

  • ロケール (そのグループに存在する場合)
  • 存在する場合は fi_FI
  • 存在しない場合は null

select
  sl.SYS_LOCALE,
  at.TEMPLATE_GROUP,
  at.TEMPLATE_NAME,
  CASE 
    WHEN EXISTS (SELECT 1 FROM AVAILABLE_TEMPLATES at_loc 
      WHERE 
        at_loc.TEMPLATE_GROUP = at.TEMPLATE_GROUP, 
        at_loc.TEMPLATE_NAME = at_fi.TEMPLATE_NAME
        at_loc.LOCALE = sl.SYS_LOCALE) 
      THEN sl.SYS_LOCALE

    WHEN EXISTS (SELECT 1 FROM AVAILABLE_TEMPLATES at_fi 
      WHERE 
        at_fi.TEMPLATE_GROUP = at.TEMPLATE_GROUP, 
        at_fi.TEMPLATE_NAME = at_fi.TEMPLATE_NAME
        at_fi.LOCALE = 'fi_FI') 
      THEN 'fi_FI'
    ELSE NULL
  END as USE_LOCALE
from SYSTEM_LOCALES sl,
    (select 
      TEMPLATE_GROUP, 
      TEMPLATE_NAME
    from AVAILABLE_TEMPLATES
    GROUP BY TEMPLATE_GROUP, TEMPLATE_NAME)
    allgroups
于 2013-03-04T14:03:23.470 に答える
1
select
   dat.template_group,
   dat.template_name,
   sl.sys_locale,
   nvl(at.locale, dat.fi_fi) as use_locale
from
   (
      select
         template_group,
         template_name,
         max(decode(locale, 'fi_FI', 'fi_FI')) as fi_fi
      from
         AVAILABLE_TEMPLATES
      group by
         template_group,
         template_name
   ) dat
   cross join SYS_LOCALE sl
   left join AVAILABLE_TEMPLATES at
      on at.template_group = dat.template_group
      and at.template_name = dat.template_name
      and at.locale = sl.sys_locale
于 2013-03-04T14:01:54.687 に答える