【发布时间】:2018-10-15 12:15:02
【问题描述】:
我需要获取表LEAVE 的每个ID 之间DATE_FROM 和DATE_TO 之间的所有日期,不包括周末、停工和节假日。考虑到这条记录(ID、DATE_FROM、DATE_TO):
001 04-OCT-2018 09-OCT-2018
002 05-OCT-2018 05-OCT-2018
...
n 01-OCT-2018 05-OCT-2018
我需要以这种格式(ID,DAY_TOKEN)获取这些范围之间的所有日期:
001 04-OCT-2018
001 05-OCT-2018
001 08-OCT-2018
001 09-OCT-2018
002 05-OCT-2018
...
n 01-OCT-2018
n 02-OCT-2018
n 03-OCT-2018
n 04-OCT-2018
n 05-OCT-2018
我正在使用根据我找到的查询修改的这个查询:
SELECT ID, a.date_from + rnum - 1 AS day_token
FROM (SELECT a.ID, a.date_from, a.date_to, ROWNUM AS rnum
FROM all_objects, leave a
-- Aside from ALL_OBJECT, I cross join it with my LEAVE table
WHERE ROWNUM <= a.date_to - a.date_from + 1) a
WHERE TO_CHAR (a.date_from + rnum - 1, 'DY') NOT IN ('SAT', 'SUN');
AND NOT EXISTS (SELECT 1
FROM holiday b
WHERE b.schedule = d.date_from + rnum - 1)
AND NOT EXISTS (SELECT 1
FROM suspension c
WHERE c.schedule = d.date_from + rnum - 1)
问题是只有第一条记录会正确展开,其他记录不会包含在记录集中,除非DATE_FROM和DATE_TO是同一日期。
我想尽可能避免使用 PL-SQL 函数,但是如果不使用函数就无法达到我需要的结果集,请至少告诉我原因。
【问题讨论】:
-
一件小事:您应该避免使用
TO_CHAR(., 'DY'),因为这会导致本地化问题。最好改用TO_CHAR(., 'D')。 -
不是一个改进,真的,@Radagast81。 ISO 标准 8601 规定星期一是一周的第一天,星期二是第二天(因此,在克罗地亚和世界大部分地区,您的查询将返回“2”,就像今天是星期二一样)。但是,加拿大、美国、澳大利亚……认为星期天是一周的第一天,所以在那里您的查询将返回“3”(它仍然是星期二,对吗?)。 'D' 由 NLS_TERRITORY 控制,但不能在 TO_CHAR 函数调用中使用;一个应该改变会话。不过,是的 - NLS_DATE_LANGUAGE 可能在 TO_CHAR 中使用并会处理。