【问题标题】:Distinct involving correlated subquery不同的涉及相关子查询
【发布时间】:2017-08-18 05:36:00
【问题描述】:

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

这是我的创建/插入:

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

如果我所做的只是从最外层的查询中删除 distinct,它会给我我预期的输出。

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

例如:

这段代码运行良好

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 的输出。 当然,如果我所做的只是从最外面的查询中删除 distinct,它就可以正常工作。

编辑:以防万一,我正在运行 Oracle 12c

【问题讨论】:

  • 那么,testing2 总是只有有最新/有效的?
  • 嗯..手头上没有播放时间 Oracle DB,但我无法在 SQL Server 中重新创建它。它不应该有什么不同,所以这很奇怪。
  • @scisimon 我使用的数据是大学的课程。 testing2 就像表中说的课程是为 Code = 'CA' in term ='300' 创建的。我需要的数据在带有通用课程信息的表中(比如它属于哪个大学)。这是名为“测试”的表。该数据是有效日期的,因为他们不想在创建的每个部分都存储所有这些信息。

标签: sql oracle


【解决方案1】:

所以我认为如果您在窗口函数中没有 ORDER BY,它使用“自然顺序”,即它们在某些情况下插入到表中的顺序,您正在使用“功能” /em>。

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

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

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

【讨论】:

  • 但是我在第一个查询的窗口函数中有一个 order by。我故意以多种方式进行测试。
  • 直接从我的问题的第一段中引用:“我只是想弄清楚为什么这种方式特别不起作用”为什么只有在删除不同时查询才有效?删除外部查询中的 distinct 会如何改变子查询返回的内容?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-07-26
  • 1970-01-01
  • 1970-01-01
  • 2012-10-18
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多