답변:
"주말"이라는 말이 토요일 과 일요일 을 의미한다고 가정하면 , 훨씬 더 간단 할 수 있습니다.
SELECT count(*) AS count_days_no_weekend
FROM generate_series(timestamp '2014-01-01'
, timestamp '2014-01-10'
, interval '1 day') the_day
WHERE extract('ISODOW' FROM the_day) < 6;
에 대한 추가 하위 쿼리 수준이 필요하지 않습니다 generate_series()
. "테이블 함수"라고도하는 SRF (세트 리턴 함수)는 FROM
절의 테이블처럼 사용할 수 있습니다 .
특히 전체 간격 (3 번째 매개 변수)이 맞는 한 출력에 상한 을 generate_series()
포함 합니다 . 상한은 마지막 간격이 잘린 경우에만 제외되며 전체 날짜의 경우에는 해당되지 않습니다.
EXTRACT () 패턴 ISODOW
을 사용하면 일요일이 7
ISO 표준에 따라로 보고됩니다 . 더 간단한 WHERE
조건을 허용합니다 .
오히려 전화 generate_series()
에 timestamp
입력. 이유는 다음과 같습니다.
count(*)
이 경우에도 약간 짧고 빠릅니다 count(the_day)
.
하한 및 / 또는 상한 을 제외 하려면 그에 따라 하루를 더하거나 빼십시오. 일반적으로 하한을 포함하고 상한을 제외 할 수 있습니다.
SELECT count(*) AS count_days_no_weekend
FROM generate_series(timestamp '2014-01-01'
, timestamp '2014-01-10' - interval '1 day'
, interval '1 day') the_day
WHERE extract('ISODOW' FROM the_day) < 6;
이 예는 2013-12-15와 2014-01-02 (포함) 사이의 모든 날짜를 열거합니다. 두 번째 열은 요일을 나타냅니다 (숫자, 0에서 6 사이). 세 번째 열은 요일이 토요일 / 일요일인지 여부를 표시하고 (주말을 고려하여 조정해야 함) 주중을 계산하는 데 사용할 수있는 항목을 나타냅니다.
select '2013-12-15'::date + i * interval '1 day',
extract('dow' from '2013-12-15'::date + i * interval '1 day') as dow,
case when extract('dow' from '2013-12-15'::date + i * interval '1 day') in (0, 6)
then false
else true end as is_weekday
from generate_series(0, '2014-01-02'::date - '2013-12-15'::date) i
;
주말이 토요일과 일요일이라고 가정하면 다음 SQL을 사용할 수 있습니다.
select count(the_day) from
(select generate_series('2014-01-01'::date, '2014-01-10'::date, '1 day') as the_day) days
where extract('dow' from the_day) not in (0,6)
날짜를 선택 사항으로 바꾸고 (0,6)을 제외하려는 요일로 바꾸십시오.
몇 가지주의해야 할 사항 :-
실행중인 PostgreSQL 버전에 대해서는 언급하지 않았습니다. 이것은 9.1 이상에서 작동하지만 하위 버전에서는 작동해야합니다.
generate_series를 사용할 때 선택한 날짜가 포함됩니다. 따라서 사이에 날짜를 원하면 각 날짜에 1 일을 추가하십시오.
이것을 쉽게하기 위해 할 수있는 몇 가지가 있습니다. 내가 사용하는 방법은 날짜 테이블을 사용할 수 있는지 확인하는 것입니다. 다음과 같이 빠르게 만들 수 있습니다.
CREATE TABLE [dbo].[Dates]
(
[Id] INT NOT NULL PRIMARY KEY IDENTITY(0,1),
[Date] Date NOT NULL unique,
isWeekend BIT NOT NULL DEFAULT(0)
)
테이블이 작성되면 비교적 빠르게 날짜 데이터로 테이블을 채울 수 있어야합니다.
set datefirst 6 --start date is saturday
INSERT INTO dbo.Dates(Date, isWeekend)
select
Date,
case datepart(weekday,date)
--relies on DateFirst being set to 6
when 2 then 1
when 1 then 1
else 0
end as isWeekend
from (
select
dateadd(day, number - 1, 0) as date
from (
SELECT top 100000 row_number() over (order by o.object_id) as number
FROM sys.objects o
cross join sys.objects b
cross join sys.objects c
)numbers
)data
그런 다음이 테이블에서 빠른 레코드 수로 쿼리를 작성할 수 있습니다.
select count(*) as NumberOfWeekDays
from dbo.dates
where isWeekend = 0
and date between '1 Jan 2013' and '31 Dec 2013'
나는 당신이 원할 때마다 사용할 함수를 작성하고 적게 쓸 것을 제안합니다. )
위의 코드는 주말 일 수를 계산하고 반환하는 sql 함수를 작성합니다 (Sat, Sun). 이 기능을 사용할 수있는 유연성이 향상되었습니다.
CREATE OR REPLACE FUNCTION <YourSchemaNameOptional>.count_full_weekend_days(date, date)
RETURNS bigint AS
$BODY$
select COUNT(MySerie.*) as Qtde
from (select CURRENT_DATE + i as Date, EXTRACT(DOW FROM CURRENT_DATE + i) as DiaDate
from generate_series(date ($1) - CURRENT_DATE, date ($2) - CURRENT_DATE ) i) as MySerie
WHERE MySerie.DiaDate in (6,0);
$BODY$
LANGUAGE 'SQL' IMMUTABLE STRICT;
그 후, 함수 를 사용하여 간격 으로 주말 수만 리턴 할 수 있습니다 . 사용하는 예제는 다음과 같습니다.
SELECT <YourSchemaNameOptional>.count_full_weekend_days('2017-09-11', '2017-09-25') as days; --> RES: 4
첫 번째와 두 번째 날이 월요일이므로이 선택은 4를 반환해야하며 두 토요일과 일요일 사이에 일요일이 있습니다.
이제, 단지 영업일 돌아갑니다 (주말없이)를 당신이 원하는대로 , 바로 아래의 예처럼 뺄셈을합니다
SELECT (date '2017-09-25' - date '2017-09-11' ) - <YourSchemaName>.count_full_weekend_days('2017-09-11', '2017-09-25'); --> RES: 14 - 4 = 10
-- Returns number of weekdays between two dates
SELECT count(*) as "numbers of days”
FROM generate_series(0, (‘from_date’::date - 'todate'::date)) i
WHERE date_part('dow', 'todate'::date + i) NOT IN (0,6)
-- Returns number of weekdays between two dates
SELECT count(*) as days
FROM generate_series(0, ('2014/04/30'::date - '2014/04/01'::date)) i
WHERE date_part('dow', '2014/04/01'::date + i) NOT IN (0,6)