首页 > 解决方案 > 选择具有正确输出的行时出现逻辑错误

问题描述

我了解基础知识,但我是 DBMS 的新手,而且我正在学习一门课程。

这是作业问题:

使用下表编写查询以显示过去 40 个月的销售额:

SALEID  SID SLDATE
1001    1   01-JAN-14
1002    5   02-JAN-14
1003    4   01-FEB-14
1004    1   01-MAR-14
1005    2   01-FEB-14
1006    1   01-JUN-15

我的查询是:

select count(sldate) as sale_count
from sale
where sldate >= add_months(sysdate, -40)

我得到的预期输出是:

SALE_COUNT
0

但我收到一条错误消息:

错误:您的查询输出与预期结果匹配,但存在逻辑错误。

我不确定我在哪里弄错了逻辑。

标签: sqldatabaseoraclerdbms

解决方案


“过去 40 个月”是模棱两可的。

对于“从日期 x 持续 n 个月意味着什么”有多种解释,而 oracle 的 add_months 对此并没有垄断(实际上大多数人会说它没有按预期工作,等到 30.06 再问有人'一个月前的日期是什么' :) )

假设今天是 4 月 20 日。“上个月”是否包括 3 月 15 日、20 日、21 日或 25 日?它包括4月2日吗?这取决于,有人可能会说“上个月”是从 3 月 21 日到 4 月 20 日。
有人可以说,从 01.03 到今天的“上个月”。
有人会说,“上个月”是从 01.04 开始的。有人会说,“上个月”是指整个三月,而不是四月的一天。

当“今天”接近月底时,情况会变得更加棘手,尤其是在三月份。

不要仅仅因为你无法读懂写作业的人的想法而对自己苛刻;)

我写了一个查询,显示不同的方法如何产生不同的结果。

CREATE OR REPLACE FUNCTION temp_can_subst_interval_months(p_date date, p_n_of_months number) RETURN NUMBER AS
V_date DATE;
BEGIN
    V_Date := p_date - (NUMTOYMINTERVAL(p_n_of_months, 'month'));
    RETURN 1;
EXCEPTION
   WHEN OTHERS THEN
      RETURN 0;
END;


with all_days as (
   select to_date('2016-01-01', 'YYYY-MM-DD') + (level - 1) as d
     from dual
    connect by level < 1462

),
all_days_2 as (
select d date_of_query_being_run,
       add_months(d, -40)as min_date_your_approach,
       add_months(d, -40) + 1 as min_date_your_approach_2, -- same, but exclude the first day
       trunc(add_months(d, -40), 'mm') as min_date_whole_month,
       case when temp_can_subst_interval_months(d, 40) = 1 then
         d - (interval '40' month)
       else null
       end as min_date_interval_approach
  from all_days ad
 order by ad.d
)
select ads.*
  from all_days_2 ads
  ;

最有趣的结果是当您的方法与区间方法不同时:

1(系统日期) 2(您的) 3 4 5(间隔)
31.01.2016 30.09.2012 01.10.2012 01.09.2012  
29.02.2016 31.10.2012 01.11.2012 01.10.2012 29.10.2012
31.03.2016 30.11.2012 01.12.2012 01.11.2012  
30.04.2016 31.12.2012 01.01.2013 01.12.2012 30.12.2012
29.06.2016 28.02.2013 01.03.2013 01.02.2013  
30.06.2016 28.02.2013 01.03.2013 01.02.2013  
31.08.2016 30.04.2013 01.05.2013 01.04.2013  
30.09.2016 31.05.2013 01.06.2013 01.05.2013 30.05.2013
31.10.2016 30.06.2013 01.07.2013 01.06.2013  
30.11.2016 31.07.2013 01.08.2013 01.07.2013 30.07.2013
31.01.2017 30.09.2013 01.10.2013 01.09.2013  
28.02.2017 31.10.2013 01.11.2013 01.10.2013 28.10.2013
31.03.2017 30.11.2013 01.12.2013 01.11.2013  
30.04.2017 31.12.2013 01.01.2014 01.12.2013 30.12.2013
29.06.2017 28.02.2014 01.03.2014 01.02.2014  
30.06.2017 28.02.2014 01.03.2014 01.02.2014  
31.08.2017 30.04.2014 01.05.2014 01.04.2014  
30.09.2017 31.05.2014 01.06.2014 01.05.2014 30.05.2014
31.10.2017 30.06.2014 01.07.2014 01.06.2014  
30.11.2017 31.07.2014 01.08.2014 01.07.2014 30.07.2014
31.01.2018 30.09.2014 01.10.2014 01.09.2014  
28.02.2018 31.10.2014 01.11.2014 01.10.2014 28.10.2014
31.03.2018 30.11.2014 01.12.2014 01.11.2014  
30.04.2018 31.12.2014 01.01.2015 01.12.2014 30.12.2014
29.06.2018 28.02.2015 01.03.2015 01.02.2015  
30.06.2018 28.02.2015 01.03.2015 01.02.2015  
31.08.2018 30.04.2015 01.05.2015 01.04.2015  
30.09.2018 31.05.2015 01.06.2015 01.05.2015 30.05.2015
31.10.2018 30.06.2015 01.07.2015 01.06.2015  
30.11.2018 31.07.2015 01.08.2015 01.07.2015 30.07.2015
31.01.2019 30.09.2015 01.10.2015 01.09.2015  
28.02.2019 31.10.2015 01.11.2015 01.10.2015 28.10.2015
31.03.2019 30.11.2015 01.12.2015 01.11.2015  
30.04.2019 31.12.2015 01.01.2016 01.12.2015 30.12.2015
30.06.2019 29.02.2016 01.03.2016 01.02.2016  
31.08.2019 30.04.2016 01.05.2016 01.04.2016  
30.09.2019 31.05.2016 01.06.2016 01.05.2016 30.05.2016
31.10.2019 30.06.2016 01.07.2016 01.06.2016  
30.11.2019 31.07.2016 01.08.2016 01.07.2016 30.07.2016

旁注:
也许该表包含“未来预期销售额”之类的内容,他们希望您过滤掉比 sysdate 晚的日期;)?


推荐阅读