优化SQL日期功能

时间:2016-10-27 13:41:24

标签: sql oracle function optimization

我编写了一个函数(Oracle SQL),它根据不同国家/地区的日历计算两个日期之间的工作日数。它需要运行数千次,因此速度非常重要。 您输入一个开始日期,结束日期和给定日历的名称,例如“US”,“UK”等。输入参数在不同的SQL中传递,但是现在我还在测试。 该功能使用假期表来查找日期之间的非工作日。该表包含不同国家的所有周末和国家法定假日。问题是尽管使用了游标,但功能很慢。有没有提示,如何使功能更快?我怀疑函数中的select查询是问题所在。我可能错了,但我不知道该怎么办。

    CREATE OR REPLACE FUNCTION Test (in_dt1         DATE,
                                                in_dt2         DATE,
                                                in_Calender    VARCHAR)
    RETURN NUMBER
    IS
    Count_days    NUMBER := 0;
    beg_dt        DATE;
    End_dt        DATE;
    Curr_dt       DATE;
    Cursor_dato   DATE;

    CURSOR C1
    IS
      SELECT b.holiday
        FROM calendars a
             INNER JOIN holidays b ON a.calik = b.calik
       WHERE a.cal = in_Calender AND holiday >= in_dt1 AND holiday <= in_dt2;
    BEGIN
      OPEN c1;

   beg_dt := LEAST (in_dt1, in_dt2);
   End_dt := GREATEST (in_dt1, in_dt2);

   Curr_dt := beg_dt + 1;

  <<OUTER>>
   WHILE Curr_dt <= End_dt
   LOOP
      FETCH c1 INTO cursor_dato;

      WHILE cursor_dato IS NULL
      LOOP
         Count_days := Count_days + 1;
         Curr_dt := Curr_dt + 1;
         EXIT OUTER WHEN Curr_dt = End_dt + 1;
      END LOOP;

      WHILE Curr_dt < cursor_dato
      LOOP
         Count_days := Count_days + 1;
         Curr_dt := Curr_dt + 1;
         EXIT OUTER WHEN Curr_dt = End_dt;
      END LOOP;

      IF Curr_dt > cursor_dato
      THEN
         Count_days := Count_days + 1;
      END IF;

      Curr_dt := Curr_dt + 1;
   END LOOP;

   CLOSE c1;

   RETURN Count_days;
END;

1 个答案:

答案 0 :(得分:5)

select trunc (end_dt) - trunc(beg_dt) from dual; 

给出两个日期之间的天数。

select count(1) from holidays where holiday >= beg_dt AND holiday <= end_dt;

给出两个日期之间的假期数。

第一 - 秒给你结果。没有游标,循环等。

类似于:

    CREATE OR REPLACE FUNCTION Test (in_dt1         DATE,
                                     in_dt2         DATE,
                                     in_Calender    VARCHAR2,
                                     p_country      varchar2)
    RETURN NUMBER
    IS
      Count_days    NUMBER := 0;
      beg_dt        DATE;
      End_dt        DATE;
      count_holidays number := 0;
    begin

      beg_dt := LEAST (in_dt1, in_dt2);
      End_dt := GREATEST (in_dt1, in_dt2);

      count_days := trunc(end_dt) - trunc(beg_dt);

      select count(1) 
      into count_holidays 
      from holidays 
      where holiday >= beg_dt
      AND holiday <= end_dt
      and country = p_country;

      return Count_days - count_holidays;
    end;

我已添加国家参数来计算正确的假期。