通过连接避免联合?

发布于 2024-08-14 09:04:27 字数 1725 浏览 5 评论 0原文

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

我有以下表格:

aa

vid   cb
---   --
  1   10
  2   15

bb

vid   cb
---   --
  3   25
  4   24

**rep*

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

以下工作: (a)

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;

My problem is on Oracle, but is probably database independent (?).

I have the following tables:

aa

vid   cb
---   --
  1   10
  2   15

bb

vid   cb
---   --
  3   25
  4   24

**rep*

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

The column p indicates in which table to get the row.
In reality, aa and bb are much more different, and p does not match to the table name, but gives a way to get there. The example is just a simplication where I have a problem.
Note than in reality, there are more than 2 tables aa and bb (there are 6).
I want a query that returns this:

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

The following works:
(a)

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

But I would like to use the query in a view, on which there can be predicate pushing.

So question 1 is: would the following allow predicate pushing.
Question 2: (even if yes for question 1) is there a way to do this without union, but with joins.
Question 3: Or just simply, a better way?

Script to create the data:

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;

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

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

发布评论

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

评论(2

从来不烧饼 2024-08-21 09:04:27

我不再有 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 的扫描中。

I don't have an Oracle instance to hand any more, but did try things with PostgreSQL, which might be of interest anyway?

My experiment with PostgreSQL suggests that actually the union works better. I created a view based on your union query, and postgres was able to push a predicate such as "cb BETWEEN 12 AND 27" into the scans of aa and bb.

By constrast, I created a view that uses joins:

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'

The problem now is that the coalesce() blocks a predicate involving cb being pushed into the scans of aa and bb.

胡大本事 2024-08-21 09:04:27

join 可以指定多个条件。表名可以是一个。例如,如果 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

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

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

A join can specify multiple conditions. The table name can be one. For example, if table1 has a column called TableName that references other tables, you could use:

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

You can add an arbitrary number of tables this way.

As to your third question, there is always a better way. The question is, does this way suffice? If not, can you define the requirements for an acceptable solution?

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