如果日期值在周末,则重置日期值
Posted
技术标签:
【中文标题】如果日期值在周末,则重置日期值【英文标题】:Resetting a date value if it falls on weekend 【发布时间】:2019-06-20 15:55:49 【问题描述】:我正在编写一个过程并使用动态游标和 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)
如果最后一个工作日是周五、周六或周日,则将传递所需的结果。
【问题讨论】:
好像不需要使用动态SQL...?您还有一个带有 order-by 子句或内联视图的 rownum 过滤器,因此它可能无法达到您的预期。无论如何,如果v_run_date
是 6 月 28 日或 29 日怎么办 - 这些也应该调整到 27 日? 8月-30日、31日应该发生的事情要调整到29日;剩下 9 月 1 日?
【参考方案1】:
你并不需要一个函数,你可以通过一个 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
是星期五、星期六或星期日,并且该月的最后一天是周五、周六或周日,然后使用该周的周四日期。
今年全年生成日期的演示:
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 代替 subquery/rownum 过滤器,但这种方法在早期版本中也可以使用。
显然,您仍然需要将其选择到变量中或将其用作游标查询 - 无论您计划动态执行什么操作。
【讨论】:
【参考方案2】:希望能解决你的问题
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)
【讨论】:
这会在每个周五/周六/周日进行调整,而不仅仅是在月末调整? (还需要注意 NLS 对“DY”产生的影响。) @AlexPoole 添加了月末条件以上是关于如果日期值在周末,则重置日期值的主要内容,如果未能解决你的问题,请参考以下文章
如果列的值在 Oracle sql 中的格式不同,则使用特定格式更新日期
java 给一个日期,往后加三天,如果是周末,节假日不算天数。直到加满三天为之,得出日期。
如果不是 NAN,则用以前的值替换 Pandas 中的缺失值