WITH range (start_date, end_date) AS (
SELECT DATE '2022-12-01', TRUNC(SYSDATE) FROM DUAL
)
SELECT -- Number of full weeks
(TRUNC(end_date, 'IW') - TRUNC(start_date, 'IW')) * 2/7
-- Number of weekend days in final week
+ GREATEST(end_date - TRUNC(end_date, 'IW') - 4, 0)
-- Number of weekend days in before first week
- GREATEST(start_date - TRUNC(start_date, 'IW') - 5, 0)
AS weekend_day_count
FROM range;
SQL> with
2 test (start_date, end_date) as
3 -- period
4 (select date '2022-12-01', date '2022-12-29' from dual),
5 calendar as
6 -- calendar (all dates between START_DATE and END_DATE)
7 (select start_date + level - 1 as datum
8 from test
9 connect by level <= end_date - start_date + 1
10 )
11 -- number of Saturdays and Sundays
12 select count(*)
13 from calendar
14 where to_char(datum, 'dy', 'nls_date_language = english') in ('sat', 'sun');
COUNT(*)
----------
8
SQL>
2条答案
按热度按时间rn0zuynd1#
不要使用行生成器来创建日历(因为它效率很低);只需通过计算整周数来计算数字,然后处理范围开始和结束时的部分周数:
其输出:
| 周末_日_计数|
| - ------|
| 八个|
fiddle
7lrncoxx2#
一个选项是在这两个日期之间创建日历,然后计算星期六和星期日的数量:
你应该在第4行更改日期。
P.S.如果你看一下代码MT 0的帖子,他们反对 * 行生成器效率低 *,这是真的。虽然两个查询返回相同的结果,但时间是不同的。例如:
很明显,“我的”时间随着周期的长度而变差。如果你看的是一年或一个世纪,差别几乎是无关紧要的。对于2000年来说,差别是“巨大的”!
但是,如果你考虑调试,从我自己的Angular 来看,my 代码更容易阅读:“从日历中选择日期为星期六或星期日的行数”-简单的英语。
另一方面,另一段代码并不那么简单;将日期截断为星期,减去它们,乘以2/7(为什么是“2/7”而不是4/9?),加上GREATEST函数返回的结果 minus 4(为什么是4?为什么不是7?),减去 something的GREATEST**minus 5(为什么是5?为什么不是2?)--正如我所说,这不容易阅读和理解。
因此,这取决于你实际需要什么,计时vs.可读性。选一个:)