Оптимизация соединения SQL (избавьтесь от UNION) - PullRequest
0 голосов
/ 09 ноября 2009

1-й отказ от ответственности:

  1. Я не программист, никогда не был
  2. никогда не учили "высшей" математике
  3. несмотря на верхние выражения, иногда мне приходится работать с SQL.

Теперь мне нужно создать view из select моих коллег (которые использовали четыре union, похоже, он не знает, как использовать or в части where ...), и теперь я здесь.

Существует ли простой читаемый способ избавиться от последнего UNION при получении того же набора результатов?

Заранее спасибо!

select a.prodt_cde,
      b.ccy,
      a.int_tabno,
      b.start_dn,
      b.end_dn,
      b.frte_term,
      b.base_id,
      b.ptvar,
      c.base_rate,
      c.desc_shnm,
      c.rel_day
 from linc.systwodb_ptico a, linc.systwodb_ptlfo b, linc.systwodb_baso c
 where a.prodt_cde in
      (select prodt_cde
         from linc.systwodb_ptmao
        where prodt_clas in (select prod_clas
                               from linc.systwodb_ramto
                              where main_type in (71, 72))
          and allow_dif in ('Y', 'M'))
  and a.int_type = 'LS'
  and a.int_tabno = b.int_tabno
  and b.ccy in
      (select ccy from linc.systwodb_ptmao where prodt_cde = a.prodt_cde)
  and b.base_id <> 0
  and b.base_id = c.base_id
  and b.ccy = c.ccy
  and ((b.end_dn = 0 and b.start_dn <= c.rel_day) or
      (b.end_dn <> 0 and b.start_dn <= c.rel_day and
      b.end_dn >= c.rel_day) or
      (b.start_dn > c.rel_day and not exists
       (select *
           from linc.systwodb_baso
          where base_id = b.base_id
            and ccy = b.ccy
            and rel_day = b.start_dn) and
       c.rel_day = (select NVL(max(rel_day), 0)
                       from linc.systwodb_baso
                      where base_id = b.base_id
                        and ccy = b.ccy
                        and rel_day < b.start_dn)))
-- 4. PTLFO.BASE_ID = 0, or cannot find BASO before PTLFO.START_DN 
union
select a.prodt_cde,
      b.ccy,
      a.int_tabno,
      b.start_dn,
      b.end_dn,
      b.frte_term,
      b.base_id,
      b.ptvar,
      0 as base_rate,
      ' ' as desc_shnm,
      0 as rel_day
 from linc.systwodb_ptico a, linc.systwodb_ptlfo b --, linc.systwodb_baso c
 where a.prodt_cde in
      (select prodt_cde
         from linc.systwodb_ptmao
        where prodt_clas in (select prod_clas
                               from linc.systwodb_ramto
                              where main_type in (71, 72))
          and allow_dif in ('Y', 'M'))
  and a.int_type = 'LS'
  and a.int_tabno = b.int_tabno
  and b.ccy in
      (select ccy from linc.systwodb_ptmao where prodt_cde = a.prodt_cde)
  and (b.base_id = 0 or not exists
       (select *
          from linc.systwodb_baso
         where base_id = b.base_id
           and ccy = b.ccy
           and rel_day <= b.start_dn))
;

1 Ответ

2 голосов
/ 09 ноября 2009

Не могли бы вы опубликовать приблизительное описание того, что это должно делать? С этим запросом очень трудно работать, не зная, что он должен делать. Основной подход к их объединению заключается в использовании явных объединений в предложении from, например:

 from
    linc.systwodb_ptico a
    INNER JOIN linc.systwodb_ptlfo b ON a.int_tabno = b.int_tabno
    LEFT OUTER JOIN linc.systwodb_baso c ON -- some kind of horrible mess here

Обратите внимание на левое внешнее соединение для systwodb_baso. Это ключевой момент для устранения другого запроса. Это обеспечит наличие строки в наборе результатов, даже если нет соответствующей записи из systwodb_baso.

Обновление:

Чтобы исключить нулевые значения из внешнего объединения, используйте функцию COALESCE:

select a.prodt_cde,
      b.ccy,
      a.int_tabno,
      b.start_dn,
      b.end_dn,
      b.frte_term,
      b.base_id,
      b.ptvar,
      COALESCE(c.base_rate, 0) AS base_rate,
      COALESCE(c.desc_shnm, ' ') AS desc_shnm,
      COALESCE(c.rel_day, 0) AS rel_day
...