暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

Oracle 在不使用子选择查询的情况下,从日期列表中查找最小日期

askTom 2018-09-28
780

问题描述

嗨,我正在做一个项目,我需要一些查询方面的帮助。

我在现有表中有以下数据:

-----------------
S_ID       S_DATE
-----------------
A         01-FEB-12
A   14-MAR-12 
A   28-APR-14 
A   28-MAR-15 
A   28-AUG-18
复制


我需要首先从S_DATE列表中找到最小日期,该列表位于S_DATE的最后2年时间范围内。所以我使用子选择查询给我的数据:

例如,第4行的S_DATE为15年3月28日,该行的2年时间范围是从2013年3月28日 (S_DATE2) 到15年3月28日 (S_DATE)。我需要从S_DATE列表中找到最小日期-这是28-APR-14 (FIRST_DATE) -> 换句话说: 28-APR-14是我可以从列表中找到的最小日期,该列表在28-MAR-13和28-MAR-15之间。

--------------------------------------------------
S_ID    S_DATE   S_DATE2  FIRST_DATE
-------------------------------------------------- 
A 01-FEB-12   01-FEB-10   01-FEB-12 
A 14-MAR-12   14-MAR-10   01-FEB-12 
A 28-APR-14   28-APR-12   28-APR-14 
A 28-MAR-15   28-MAR-13   28-APR-14 
A 28-AUG-18   28-AUG-16   28-AUG-18
复制


然后我需要做的下一件事是从S_DATE列表中找到最小日期,这是在过去3年的时间范围内。我必须使用另一个子查询来获取日期:

对于相同的示例,第4行。3年的时间范围是从28 APR-11 (FIRST_DATE3) 到28 APR-14 (FIRST_DATE),S_DATE列表中的最小日期是01 FEB-12。
--------------------------------------------------------------------------------------
S_ID  S_DATE     S_DATE2  FIRST_DATE FIRST_DATE3 FIRST_DATE_IN3
--------------------------------------------------------------------------------------
A 01-FEB-12   01-FEB-10   01-FEB-12   01-FEB-09   01-FEB-12
A 14-MAR-12   14-MAR-10   01-FEB-12   01-FEB-09   01-FEB-12
A 28-APR-14   28-APR-12   28-APR-14   28-APR-11   01-FEB-12
A 28-MAR-15   28-MAR-13   28-APR-14   28-APR-11   01-FEB-12
A 28-AUG-18   28-AUG-16   28-AUG-18   28-AUG-15   28-AUG-18 
复制



下面是这个例子的我的代码:

SELECT Q.*,
ADD_MONTHS(Q.FIRST_DATE,-12*3) AS FIRST_DATE3,

(
SELECT MIN(S1.S_DATE)
  FROM SAMPLE_TEST S1
 WHERE S1.S_ID=Q.S_ID
   AND S1.S_DATE>=ADD_MONTHS(Q.FIRST_DATE,-12*3)
   AND S1.S_DATE<=Q.FIRST_DATE
) AS FIRST_DATE_IN3

FROM(

SELECT 

S.S_ID,
S.S_DATE,
ADD_MONTHS(S.S_DATE,-12*2) AS S_DATE2,
(
SELECT MIN(S1.S_DATE)
  FROM SAMPLE_TEST S1
 WHERE S1.S_ID=S.S_ID
   AND S1.S_DATE>=ADD_MONTHS(S.S_DATE,-12*2)
   AND S1.S_DATE<=S.S_DATE
) AS FIRST_DATE


FROM SAMPLE_TEST S
)Q

ORDER BY Q.S_DATE
复制



这只是一个简单的例子,所以我没有任何问题与子选择查询。但我的真实数据集包含超过60,000行。对于每个S_ID,我有成千上万的日期来进行这些逻辑检查。子查询的查询运行速度非常慢。我是SQL新手,在网上没有找到任何有用的建议。所以请帮我这个!我真的很感激你的时间和努力!

我想知道还有其他方法可以得到相同的结果吗?如果我使用视图或存储过程,会有所帮助吗?



谢谢!

专家解答

因此,您想在与当前行的时间范围偏移量内的数据中找到最小日期?

如果是这样,则不需要子查询。解析函数就是答案!

在min() 之后添加over子句,并按日期排序。

然后将window子句设置为

range between N preceding and current row
复制


这将把日期N在当前之前的所有行传递给min。其中最早发现:

create table sample_test   (     
  s_id  varchar(10),     
  s_date  date   
);

insert into sample_test values ('A', to_date('01-feb-2012','dd-mon-yyyy'));
insert into sample_test values ('A', to_date('14-mar-2012','dd-mon-yyyy'));
insert into sample_test values ('A', to_date('28-mar-2015','dd-mon-yyyy'));
insert into sample_test values ('A', to_date('28-aug-2018','dd-mon-yyyy'));
commit;

select s_date, 
       min ( s_date ) over ( 
         order by s_date 
           range between ( s_date - add_months ( s_date, -24 ) ) preceding 
                 and current row 
       ) min_2_year   , 
       min ( s_date ) over ( 
         order by s_date 
           range between ( s_date - add_months ( s_date, -36 ) ) preceding 
                 and current row 
       ) min_3_year
from   sample_test;


S_DATE                 MIN_2_YEAR             MIN_3_YEAR             
01-FEB-2012 00:00:00   01-FEB-2012 00:00:00   01-FEB-2012 00:00:00   
14-MAR-2012 00:00:00   01-FEB-2012 00:00:00   01-FEB-2012 00:00:00   
28-MAR-2015 00:00:00   28-MAR-2015 00:00:00   28-MAR-2015 00:00:00   
28-AUG-2018 00:00:00   28-AUG-2018 00:00:00   28-AUG-2018 00:00:00 
复制

「喜欢这篇文章,您的关注和赞赏是给作者最好的鼓励」
关注作者
【版权声明】本文为墨天轮用户原创内容,转载时必须标注文章的来源(墨天轮),文章链接,文章作者等基本信息,否则作者和墨天轮有权追究责任。如果您发现墨天轮中有涉嫌抄袭或者侵权的内容,欢迎发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论