我在生产数据库中遇到了这个问题,并花了一些时间使用新创建的表重新创建它。我意识到这些查询可以用不同的方式编写,但我只是想弄清楚为什么这种方式特别不起作用,因为这种代码在我们的整个生产数据库中都充斥着。
以下是我的创建/插入:
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
答案 0 :(得分:0)
所以我认为你正在使用&#34;功能&#34;如果你在窗口函数中没有ORDER BY,它会使用&#34;自然顺序&#34;这是他们在某些情况下插入表的顺序。
这是不可取的。它停止使用子查询的原因是因为内存结果没有自然顺序。订单将是随机的。
事实上,自然顺序可以是随机的(特别是如果表跨越磁盘或服务器或分片或其他任何东西 - 你依靠硬件来订购。硬件可能很复杂。)
你真正想要的是一个真实的订单。有一个Timestamp列,在插入时设置为默认值。然后你总是知道什么时候插入它,你可以按那个列排序。