SQL 连接优化(摆脱 UNION)

发布于 2024-08-10 07:51:14 字数 2666 浏览 2 评论 0原文

第一个免责声明:

  1. 我不是程序员,从来没有
  2. 被教过“高等”数学,
  3. 尽管上面的陈述有时我必须使用 SQL。

现在,我需要从我的同事的 select 中创建一个 view(他使用了四个 union ,看起来他不知道如何使用在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))
;

1st disclaimers:

  1. I'm not a programmer, never was
  2. had never been taught "higher" math
  3. despite the upper statements sometimes I have to work with SQL.

Now I need to create a view from a select of my colleagues (who had used four unions looked like he do not know how to use or in the where part...), and now I'm here.

Is there a simple readable way of getting rid of the last UNION while getting the same result set?

Thanks in advance!

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))
;

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

一场信仰旅途 2024-08-17 07:51:14

您能否发布一个粗略的描述来说明这应该做什么?如果不知道它应该做什么,这个查询就很难使用。组合这些的基本方法是在 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

Could you post a rough description of what this is supposed to to do? This query is very difficult to work with without knowing what it's supposed to be doing though. The basic approach to combining these will be to use explicit joins in the from clause like so:

 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

Note the left outer join for systwodb_baso. That's the key point for eliminating the other query. That will ensure there is a row in the result set even if there is no matching record from systwodb_baso.

Update:

In order to eliminate null values from the outer join, use the COALESCE function:

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
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文