我正在编写一个过程,并使用动态游标和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)
如果最后一个工作日是周五,周六或周日,则期望的结果将通过星期四的日期传递。
答案 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
...
如评论中所述,您的代码似乎不需要动态;您可以对显示的内容使用静态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代替子查询/行数过滤器,但是这种方法将在早期版本中起作用。
显然,您仍然需要将其选择为变量或将其用作游标查询-无论您打算动态执行什么操作。