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

我希望通过加入这两个表来获得的数据应该具有表中行的笛卡尔积和表中的SYS_LOCALE不同TEMPLATE_GROUP/ 。TEMPLATE_NAMEAVAILABLE_TEMPLATES

我们的默认语言环境是fi_FI. 对于TEMPLATE_NAMEa 中的每个TEMPLATE_GROUP,我想检查一个匹配的语言环境是否可用,如果是,它应该返回为USE_LOCALE. 如果找不到匹配的语言环境,我想返回系统的默认语言环境,即fi_FI它是否存在于TEMPLATE_NAMEand TEMPLATE_GROUPas 中USE_LOCALE

以下是加入这两个表应该返回的内容:

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.

这是表只被扫描一次的证据:

    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
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 回答
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 回答