Я намагаюся визначити кількість днів між двома різними датами, крім вихідних.
Я не знаю, як досягти цього результату.
Я намагаюся визначити кількість днів між двома різними датами, крім вихідних.
Я не знаю, як досягти цього результату.
Відповіді:
Якщо припустити, що під вихідними ви маєте на увазі суботу та неділю , це може бути ще простіше:
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
пункті.
Зокрема, зверніть увагу на те, що generate_series()
включає верхню межу у висновку, якщо відповідає повний інтервал (3-й параметр). Верхня межа виключається лише в тому випадку, якщо останній інтервал буде урізаний, що не стосується повних днів.
З малюнком ISODOW
для ЕКСТРАКТУ () , неділя , як повідомляється 7
, в відповідності зі стандартом ISO. Дозволяє для більш простої WHERE
умови.
Скоріше дзвінок generate_series()
із timestamp
введенням. Ось чому:
count(*)
трохи коротше і швидше, ніж count(the_day)
це робити в цьому випадку.
Щоб виключити нижню та / або верхню межу, додайте / віднімайте відповідно 1 день. Як правило, ви можете включати нижню та виключати верхню межу:
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+, але має працювати на нижчих версіях.
Вибрані дати включаються при використанні файлу Generator_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, яка підраховує та повертає кількість днів вихідних (сб, нд). Просто так ви будете мати більшу гнучкість для використання цієї функції.
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
Цей вибір повинен повернути чотири, тому що перший та другий день - понеділок, а між нами 2 суботи та 2 неділі.
Тепер, щоб повернути лише робочі дні (без вихідних), як вам потрібно , просто зробіть віднімання, як на прикладі нижче:
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)