涉及相关子查询的区别

时间:2017-08-17 20:52:03

标签: sql oracle

我在生产数据库中遇到了这个问题,并花了一些时间使用新创建的表重新创建它。我意识到这些查询可以用不同的方式编写,但我只是想弄清楚为什么这种方式特别不起作用,因为这种代码在我们的整个生产数据库中都充斥着。

以下是我的创建/插入:

create table Testing
(
    Code varchar2(50),
    EffTerm varchar2(50),
    Value varchar2(50)
);

create table Testing2
(
    Code varchar2(50),
    Term varchar2(50)
);

insert into Testing
values('CA',100,1);
insert into Testing
values('CA',200,2);
insert into Testing
values('CB',100,3);
insert into Testing
values('CC',100,4);

insert into Testing2
values('CA',300);
insert into Testing2
values('CB',300);
insert into Testing2
values('CC',300);

我的想法是,我正在尝试获取每个“代码”的最新行。表Testing2是具有这些任意代码的当前历史的表。为了获得该代码的最新“价值”,我需要获得最新的有效期限(此处表示为100,200,300)。

我的生产数据库中最像我原始问题的查询如下所示:

select distinct VALUE
from Testing2
join Testing on Testing2.Code = Testing.Code
where Testing2.Term = 300
and Testing.EFFTERM = (select A.EFFTERM from
                        (select T.EFFTERM,
                                rank() over(order by T.EFFTERM desc) rowRank
                         from Testing T
                        where T.CODE = Testing.CODE
                          and T.EFFTERM <= Testing2.Term) A
                        where rowRank = 1)
order by 1;

此示例的当前术语是300(Testing2表中的值)。为了获得有效的术语,它使用窗口函数对术语降序进行排名,并通过将其包装在select语句中来选择最大的术语。运行此特定代码可以得到以下输出:

Value
1
2
3
4

我的预期输出是:

Value
2
3
4

如果我所做的就是从最外面的查询中删除不同的内容,它会给我预期的输出。

经过一些更多的测试,我认为它与窗口函数有关,而且相关的子查询是一个额外的级别。

例如:

此代码完美无缺

select distinct VALUE
from Testing2
join Testing on Testing2.Code = Testing.Code
where Testing2.Term = 300
and Testing.EFFTERM = (select distinct max(T.EFFTERM) over() EFFTERM
                         from Testing T
                        where T.CODE = Testing.CODE
                          and T.EFFTERM <= Testing2.Term)
order by 1;

但是第二个我将子查询包装在另一个选择中:

select distinct VALUE
from Testing2
join Testing on Testing2.Code = Testing.Code
where Testing2.Term = 300
and Testing.EFFTERM = (select A.effterm from
                       (select distinct max(T.EFFTERM) over() EFFTERM
                         from Testing T
                        where T.CODE = Testing.CODE
                          and T.EFFTERM <= Testing2.Term) A)
order by 1;

它回馈给我1,2,3,4的输出。 当然,如果我所做的就是删除与最外层查询不同的区别,那么它可以正常工作。

编辑:万一重要,我正在运行Oracle 12c

1 个答案:

答案 0 :(得分:0)

所以我认为你正在使用&#34;功能&#34;如果你在窗口函数中没有ORDER BY,它会使用&#34;自然顺序&#34;这是他们在某些情况下插入表的顺序

这是不可取的。它停止使用子查询的原因是因为内存结果没有自然顺序。订单将是随机的。

  

事实上,自然顺序可以是随机的(特别是如果表跨越磁盘或服务器或分片或其他任何东西 - 你依靠硬件来订购。硬件可能很复杂。)

你真正想要的是一个真实的订单。有一个Timestamp列,在插入时设置为默认值。然后你总是知道什么时候插入它,你可以按那个列排序。