重置日期值(如果它在周末)

时间:2019-06-20 15:55:49

标签: sql oracle

我正在编写一个过程,并使用动态游标和SQL查询,并将它们作为字符串传递给V_SQL变量。查询如下:

在where条件中,我正在传递日期,但条件是,如果它是月末并且是星期五,星期六或星期日,则将其重置为星期四。例如,6月30日将是星期日,因此在SQL查询中传递给day_of_month的值应为27,即从星期四开始的天数。

请帮助我编写单独的函数是否会好,我应该输入什么代码以获得更好的性能和所需的结果。

V_SQL := 'SELECT B.FIN_ELEM, A.ORG_UNIT_ID, A.GL_ACCOUNT_ID, B.CMN_COA_ID, B.PROD1, B.PROD2, B.PROD3, '||
'A.AS_OF_DATE, SUM(CURRENT_BAL) AS CB_SUM, SUM(AVG_BAL) AS AB_SUM, B.FLAG1 FROM DAILYGL A, AL_LOOKUP B '||
'WHERE A.GL_ACCOUNT_ID = B.GL_ACCT ***AND DAY_OF_MONTH = '|| TO_DO_FUNCTION(V_RUN_DATE)***

' AND ROWNUM <=15 GROUP BY B.FIN_ELEM, A.ORG_UNIT_ID, A.GL_ACCOUNT_ID,B.CMN_COA_ID, B.PROD1, B.PROD2, B.PROD3';

DAY_OF_MONTH ='|| TO_DO_FUNCTION(V_RUN_DATE)

如果最后一个工作日是周五,周六或周日,则期望的结果将通过星期四的日期传递。

2 个答案:

答案 0 :(得分:0)

我希望这可以解决您的问题

V_RUN_DATE - (case when V_RUN_DATE > LAST_DAY (V_RUN_DATE)- 3 then  V_RUN_DATE else  
 (case TO_CHAR(date V_RUN_DATE, 'DY') when  'FRI' then 1 when 'SAT' then 2 when 'SUN' then 3 else 0 end) end)

答案 1 :(得分:0)

您实际上并不需要功能,可以使用case表达式来实现此功能,例如:

AND DAY_OF_MONTH = case
    when last_day(v_run_date) - v_run_date <= 3
      and to_char(v_run_date, 'Dy', 'NLS_DATE_LANGUAGE=ENGLISH') in ('Fri', 'Sat', 'Sun')
      and to_char(last_day(v_run_date), 'Dy', 'NLS_DATE_LANGUAGE=ENGLISH') in ('Fri', 'Sat', 'Sun')
    then next_day(trunc(v_run_date, 'IW'), 'THURSDAY')
    else v_run_date
  end

也就是说,如果v_run_date在每月的最后一天的三天内,则 v_run_date是星期五,星期六或星期日,和< / em>该月的最后一天是星期五,星期六或星期日,然后使用该星期四的日期。

具有今年全年生成的日期的演示:

with cte (v_run_date) as (
  select date '2018-12-31' + level
  from dual
  connect by level <= 365
)
select v_run_date,
  to_char(v_run_date, 'Dy', 'NLS_DATE_LANGUAGE=ENGLISH') as dy,
  case
    when last_day(v_run_date) - v_run_date <= 3
      and to_char(v_run_date, 'Dy', 'NLS_DATE_LANGUAGE=ENGLISH') in ('Fri', 'Sat', 'Sun')
      and to_char(last_day(v_run_date), 'Dy', 'NLS_DATE_LANGUAGE=ENGLISH') in ('Fri', 'Sat', 'Sun')
    then next_day(trunc(v_run_date, 'IW'), 'THURSDAY')
    else v_run_date
  end as adjusted_date
from cte;

V_RUN_DATE DY           ADJUSTED_D
---------- ------------ ----------
2019-01-01 Tue          2019-01-01
2019-01-02 Wed          2019-01-02
...
2019-01-30 Wed          2019-01-30
2019-01-31 Thu          2019-01-31
2019-02-01 Fri          2019-02-01
2019-02-02 Sat          2019-02-02
...
2019-03-26 Tue          2019-03-26
2019-03-27 Wed          2019-03-27
2019-03-28 Thu          2019-03-28
2019-03-29 Fri          2019-03-28
2019-03-30 Sat          2019-03-28
2019-03-31 Sun          2019-03-28
2019-04-01 Mon          2019-04-01
...
2019-04-30 Tue          2019-04-30
2019-05-01 Wed          2019-05-01
...
2019-05-28 Tue          2019-05-28
2019-05-29 Wed          2019-05-29
2019-05-30 Thu          2019-05-30
2019-05-31 Fri          2019-05-30
2019-06-01 Sat          2019-06-01
2019-06-02 Sun          2019-06-02
...
2019-06-26 Wed          2019-06-26
2019-06-27 Thu          2019-06-27
2019-06-28 Fri          2019-06-27
2019-06-29 Sat          2019-06-27
2019-06-30 Sun          2019-06-27
2019-07-01 Mon          2019-07-01
...
2019-07-31 Wed          2019-07-31
2019-08-01 Thu          2019-08-01
...
2019-08-28 Wed          2019-08-28
2019-08-29 Thu          2019-08-29
2019-08-30 Fri          2019-08-29
2019-08-31 Sat          2019-08-29
2019-09-01 Sun          2019-09-01
...
2019-11-27 Wed          2019-11-27
2019-11-28 Thu          2019-11-28
2019-11-29 Fri          2019-11-28
2019-11-30 Sat          2019-11-28
2019-12-01 Sun          2019-12-01
...

db<>fiddle


如评论中所述,您的代码似乎不需要动态;您可以对显示的内容使用静态SQL,例如:

SELECT *
-- into ...
FROM (
  SELECT B.FIN_ELEM, A.ORG_UNIT_ID, A.GL_ACCOUNT_ID,
    B.CMN_COA_ID, B.PROD1, B.PROD2, B.PROD3, A.AS_OF_DATE,
    SUM(CURRENT_BAL) AS CB_SUM, SUM(AVG_BAL) AS AB_SUM, B.FLAG1
  FROM DAILYGL A
  JOIN AL_LOOKUP B ON B.GL_ACCT = A.GL_ACCOUNT_ID
  WHERE DAY_OF_MONTH = case
      when last_day(v_run_date) - v_run_date <= 3
        and to_char(v_run_date, 'Dy', 'NLS_DATE_LANGUAGE=ENGLISH') in ('Fri', 'Sat', 'Sun')
        and to_char(last_day(v_run_date), 'Dy', 'NLS_DATE_LANGUAGE=ENGLISH') in ('Fri', 'Sat', 'Sun')
      then next_day(trunc(v_run_date, 'IW'), 'THURSDAY')
      else v_run_date
    end
  GROUP BY B.FIN_ELEM, A.ORG_UNIT_ID, A.GL_ACCOUNT_ID,B.CMN_COA_ID, B.PROD1, B.PROD2, B.PROD3
  -- order by something...
)
WHERE ROWNUM <= 15;

我也切换到ANSI联接,但更重要的是将主查询移到了内联视图,然后对其应用了rownum过滤器;除非/直到您在该内联视图内添加order-by子句,否则这没有什么不同。没有它,您的原始图像将获得不确定的(不是很随机,但效果相似)的一组15行。如果您订购内部查询,那么将始终根据您的订购条件获得前15行。从12c开始,您可以使用a row limiting clause代替子查询/行数过滤器,但是这种方法将在早期版本中起作用。

显然,您仍然需要将其选择为变量或将其用作游标查询-无论您打算动态执行什么操作。