【问题标题】:Avoiding union by join?通过加入避免联合?
【发布时间】:2009-12-15 23:44:14
【问题描述】:

我的问题出在 Oracle 上,但可能与数据库无关 (?)。

我有以下表格:

aa

vid   cb
---   --
  1   10
  2   15

bb

vid   cb
---   --
  3   25
  4   24

**代表*

repid  vid   p
-----  ---  --
   99    1  aa
   99    2  aa
   99    3  bb
   99    4  bb

列 p 表示在哪个表中获取该行。 实际上,aa 和 bb 的区别要大得多,并且 p 与表名不匹配,但提供了一种到达那里的方法。这个例子只是我遇到问题的一个简单的例子。 请注意,实际上,有超过 2 个表 aa 和 bb(有 6 个)。 我想要一个返回这个的查询:

repid  vid   p  cb
-----  ---  --  --
   99    1  aa  10
   99    2  aa  15
   99    3  bb  25
   99    4  bb  24

以下作品: (一)

select rep.vid, rep.p, cb 
from (
select 'aa' as p,vid,cb from aa
union all 
select 'bb' as p, vid,cb from bb) u,rep
where rep.p=u.p and rep.vid=u.vid

(b)

select rep.vid, rep.p, 
   decode(rep.p, 'aa', (select cb from aa where vid=rep.vid), 
                 'bb', (select cb from bb where vid=rep.vid)) cb
from rep

但我想在视图中使用查询,在该视图上可以进行谓词推送。

所以问题 1 是:以下是否允许谓词推送。 问题 2:(即使问题 1 的答案是肯定的)有没有办法在没有联合但有连接的情况下做到这一点。 问题 3:或者只是一个更好的方法?

创建数据的脚本:

create table bb (vid number(1), cb number(2));
create table aa (vid number(1), cb number(2));
create table rep(rid number(2), vid number(1), p varchar2(2));
insert into rep (rid,vid,p) values (99, 4,'bb');
insert into rep (rid,vid,p) values (99, 3,'bb');
insert into rep (rid,vid,p) values (99, 2,'aa');
insert into rep (rid,vid,p) values (99, 1,'aa');
insert into bb (vid,cb) values (4,24);
insert into bb (vid,cb) values (3,25);
insert into aa (vid,cb) values (2,15);
insert into aa (vid,cb) values (1,10);
commit;

【问题讨论】:

  • 您可以控制架构吗?我假设您不能更改任何表格?
  • 正确:表格已经存在,我无法更改它们。

标签: sql join union push predicate


【解决方案1】:

我没有要处理的 Oracle 实例了,但我尝试过 PostgreSQL 的一些东西,这可能还是会感兴趣的?

我对 PostgreSQL 的实验表明,实际上联合工作得更好。我根据您的联合查询创建了一个视图,并且 postgres 能够将诸如“cb BETWEEN 12 AND 27”之类的谓词推送到 aa 和 bb 的扫描中。

相比之下,我创建了一个使用连接的视图:

create view rep2 as
  select rep.vid, p, coalesce(aa.cb, bb.cb) as cb
  from rep
       left join aa on aa.vid = rep.vid and rep.p = 'aa'
       left join bb on bb.vid = rep.vid and rep.p = 'bb'

现在的问题是,coalesce() 阻止了一个涉及 cb 的谓词被推入 aa 和 bb 的扫描中。

【讨论】:

    【解决方案2】:

    join 可以指定多个条件。表名可以是 1。例如,如果table1 有一个名为TableName 的列引用其他表,则可以使用:

    select      *
    from        table1 t1
    left join   table2 t2
    on          t1.TableName = 'table2'
                and t1.id = t2.id
    left join   table3 t3
    on          t1.TableName = 'table3'
                and t1.id = t3.id
    

    您可以通过这种方式添加任意数量的表格。

    关于你的第三个问题,总有更好的方法。问题是,这样就够了吗?如果不是,您能否定义可接受的解决方案的要求?

    【讨论】:

    • 是的,如果表格有一个名为 tableName 的列,那肯定会有所帮助。问题是他们没有。我想一种解决方案是围绕这些表创建视图并包含 tableName(或等效项)。
    • @Nicolas:您的表“rep”包含一个带有表名的字段“pp”?
    • 实际上,根据 p 的值,您将拥有 table1 的列 cb 或 table2 的 cb 而不是 *。这是问题的很大一部分:“合并”来自不同表的列。
    • 对不起,我刚刚错过了您的评论。能否请您对我提供的表格进行查询?
    • @Nicolas:araqnid 的回答展示了如何使用coalesce从许多左连接中选择一列
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-10-01
    • 1970-01-01
    • 1970-01-01
    • 2011-04-09
    • 2012-12-17
    • 2016-11-22
    • 2019-05-29
    相关资源
    最近更新 更多