Oracle sql周期添加问题

时间:2014-11-12 11:08:45

标签: oracle

我有一个周期存储在数据库中,周期是在VARCHAR2()

示例:2014019  它表示2014年的第19周

我想在周期间做加/减操作,2014019 + 1将是2014020

但我不能正常加/减,因为2014052(2014年的最后一周)+ 1 = 2014053这是错误的。

2014052 + 1 = 2015001这是正确的。

知道如何使用sql / store过程解决这个问题?

3 个答案:

答案 0 :(得分:0)

如果你总是有相同的长度字符串(4位+'0'+ 2位),你可以简单地将其子串: (增加闰年逻辑)

DECLARE lvchInput   VARCHAR2(7);
        lvchOutput  VARCHAR2(7);
        lnYear      NUMBER;
        lnWeek      NUMBER;
        lbLeap      BOOLEAN;

BEGIN
    lvchInput := '2012052';
    lnYear := to_number(SubStr(lvchInput, 1, 4));
    lnWeek := to_number(SubStr(lvchInput, 6, 2));

    IF (Mod(lnYear, 4) = 0 AND Mod(lnYear, 100) <> 0) OR Mod(lnYear, 400) = 0 THEN
        lbLeap := TRUE;
    ELSE
        lbLeap := FALSE;
    END IF; 

    DBMS_OUTPUT.PUT_LINE('lbLeap = ' || CASE WHEN lbLeap = TRUE THEN 'True' ELSE 'False' END);
    DBMS_OUTPUT.PUT_LINE('lnYear = ' || to_char(lnYear));
    DBMS_OUTPUT.PUT_LINE('lnWeek = ' || to_char(lnWeek));

    IF (lbLeap AND lnWeek >= 53) OR 
       (NOT lbLeap AND lnWeek >= 52) THEN
        lnWeek := 0;
        lnYear := lnYear + 1;
    END IF;
    lnWeek := lnWeek + 1;

    lvchOutput := to_char(lnYear) || '0' || LPad(to_char(lnWeek), 2, '0');
    DBMS_OUTPUT.PUT_LINE('lvchOutput = ' || lvchOutput);
END;

答案 1 :(得分:0)

编辑:增加OP要求的闰年条件。

编辑2:忘记检查YEAR之后的新年份:=年+ 1是闰年。添加了条件和测试用例。

CREATE OR REPLACE FUNCTION ADD_WEEK (p_date IN VARCHAR2, nrOfWeeks IN NUMBER)
   RETURN VARCHAR2
AS
   RESULT       VARCHAR2 (8);
   YEAR         NUMBER;
   WEEK         NUMBER;
   LEAP_LIMIT   NUMBER;
BEGIN
   YEAR := SUBSTR (p_date, 1, 4);
   WEEK := SUBSTR (p_date, 6, 2);

   IF (MOD (YEAR, 400) = 0)
   THEN
      LEAP_LIMIT := 54;
   ELSIF (MOD (YEAR, 100) = 0)
   THEN
      LEAP_LIMIT := 53;
   ELSIF (MOD (YEAR, 4) = 0)
   THEN
      LEAP_LIMIT := 54;
   ELSE
      LEAP_LIMIT := 53;
   END IF;

   FOR i IN 1 .. nrOfWeeks
   LOOP
      WEEK := WEEK + 1;

      IF WEEK >= LEAP_LIMIT
      THEN
         WEEK := 1;
         YEAR := YEAR + 1;
      END IF;

   --check if the resulted year is a leap year before reentering the loop
   IF (MOD (YEAR, 400) = 0)
   THEN
      LEAP_LIMIT := 54;
   ELSIF (MOD (YEAR, 100) = 0)
   THEN
      LEAP_LIMIT := 53;
   ELSIF (MOD (YEAR, 4) = 0)
   THEN
      LEAP_LIMIT := 54;
   ELSE
      LEAP_LIMIT := 53;
   END IF;  

   END LOOP;

   RESULT :=
         YEAR
      || '0'
      || (CASE
             WHEN week < 10 THEN '0' || TO_CHAR (week)
             ELSE TO_CHAR (week)
          END);
   RETURN RESULT;
END ADD_WEEK;

例如可以调用(根据需要添加多周)

 select  ADD_WEEK('2014052',2) AS RESULT from dual

产生

的结果
2015002

闰年

select  ADD_WEEK('2012052',1) AS RESULT from dual

输出:

2012053

增加许多周并跟踪闰年

2012 -53
2013 -52
2014 -52
2015 -52
total of 53+3*52=209 weeks, should give result of 2016001 if starting from 2012001

select  ADD_WEEK('2012001',209) AS RESULT from dual

结果是:

2016001

答案 2 :(得分:0)

create or replace function add_weeks(f_week_period in varchar2, f_weeks_to_add NUMBER, f_fmt varchar2) return varchar2 as 
  l_year  integer;
  l_weeks integer;
  l_last  integer;
begin
  l_year := to_number(substr(f_week_period, 1, 4));
  l_weeks := to_number(substr(f_week_period, -2, 2)) + f_weeks_to_add;

  while true loop
    -- get the max number of weeks in the year
    l_last := to_number(to_char(to_date(l_year || '1231', 'YYYYMMDD'), f_fmt));
    -- IW can return 1
    if l_last = 1 then
      l_last := to_number(to_char(to_date(l_year || '1224', 'YYYYMMDD'), f_fmt));  
    end if;
    if (l_last >= l_weeks) then
      exit;
    else 
      l_weeks := l_weeks - l_last;
      l_year := l_year + 1;
    end if;
  end loop;
  return l_year || '0' || l_weeks;  
end add_weeks;

用法:

-- ISO weeks
select add_weeks('2014019', 50, 'IW') from dual;

-- WW weeks
select add_weeks('2014019', 50, 'WW') from dual;

功能仅适用于正f_weeks_to_add(但修改它以使用负数并不困难)。

f_fmt可以使用&#39; WW&#39;或者&#39; IW&#39;