【问题标题】:PL SQL Function while loop ending unexpectedlyPL SQL函数while循环意外结束
【发布时间】:2013-04-03 18:08:54
【问题描述】:

我有一个函数,我想计算两个日期之间的秒数,这些秒数应该只在我们公司的营业时间内计算。因为完成任务可能需要几天时间,所以我创建了一个 while 循环,应该增加天数

这是我的循环:

    WHILE TO_DATE(TRUNC(dateIterator),'YYYY-MM-DD') < TO_DATE(TRUNC(CallbackUpdatedDate),'YYYY-MM-DD') LOOP
 calculateIntervalFrom := null;
calculateIntervalTo := null;

SELECT THIS_DATE_OPENING,
 THIS_DATE_CLOSING,
 NEXT_DATE_OPENING
INTO thisDateOpening, thisDateClosing, nextDay
FROM KS_DRIFT.SYS_DATE_KS
WHERE THIS_DATE = dateIterator;

-- gets calculated from
calculateIntervalFrom := thisDateOpening;

-- Gets calculateTo
IF dateIterator = TO_DATE(TRUNC(CallbackUpdatedDate),'YYYY-MM-DD') THEN
calculateIntervalTo := CallbackUpdatedDate;
ELSE
calculateIntervalTo := thisDateClosing;
END IF;
fromSeconds := abs(extract(second from TO_TIMESTAMP(calculateIntervalFrom))) + extract(minute from TO_TIMESTAMP(calculateIntervalFrom)) * 60 + extract(hour from TO_TIMESTAMP(calculateIntervalFrom)) * 60 * 60;
toSeconds :=abs(extract(second from TO_TIMESTAMP(calculateIntervalTo))) + extract(minute from TO_TIMESTAMP(calculateIntervalTo)) * 60 + extract(hour from TO_TIMESTAMP(calculateIntervalTo)) * 60 * 60;
intervalDifference := fromSeconds - toSeconds;

solvedSeconds := solvedSeconds + intervalDifference;
dateIterator := nextDay;
dbms_output.put_line(nextDay);

小解释

所以我们的想法是,只要值 dateIterator(即创建行的日期)与上次更新行的时间(CallbackUpdatedDate)不同,它就会选择今天并且隔天营业时间从表KS_DRIFT.SYS_DATE_KS

如果今天与CallbackUpdatedDate 相同,它将设置calculateIntervalTo 等于CallbackUpdatedDate,否则将值设置为thisDateClosing

然后它将计算两个日期之间的秒数并将它们添加到NUMBER solvedSeconds

之后我会将dateIterator设置为下一个开放日:dateIterator := nextDay;

这有效,但只有两次,然后它只是结束循环:

这是它尝试计算的两个日期:

创建时间:2013-03-26 10:23:33

最后更新时间:2013-04-03 09:25:10

dbms_output.put_line(nextDay); outputs these two values: 

2013-03-27 和 2013-03-27

从表面上看,while 循环中的 SELECT 语句似乎没有按预期工作,但我根本不明白为什么?

【问题讨论】:

    标签: sql function plsql while-loop


    【解决方案1】:

    为什么不使用 WHILE 循环,而不是只使用单个查询?比如:

    select (end_date - start_date - 
            (select coalesce(sum(least(NEXT_DATE_OPENING,end_date) -
                                 greatest(THIS_DATE_CLOSING,start_date)),0)
             from KS_DRIFT.SYS_DATE_KS
             where THIS_DATE_CLOSING < end_date and 
                   NEXT_DATE_OPENING > start_date)) * 86400 available_time
    from dual
    

    SQLFiddle here.

    【讨论】:

      【解决方案2】:

      你对待日期的方式看起来很奇怪:

      TO_DATE(TRUNC(dateIterator),'YYYY-MM-DD') 
      

      所以 dateIterator 是您截断的日期,即您删除时间部分。这为您提供了一个时间设置为 00:00:00 的日期。但是随后您在该日期使用 to_date 函数,就好像它是一个字符串一样。这在我看来是错误的。

      然后在你的选择语句中你有

      WHERE THIS_DATE = dateIterator
      

      我想知道:上面你必须从 dateIterator 中删除时间。在这里你没有。您的表是否包含包含时间部分的 dateIterator 条目?

      我希望这些发现已经有助于解决问题。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2012-10-04
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-12-29
        • 2018-09-01
        • 2013-12-22
        相关资源
        最近更新 更多