Рассчитать разницу между двумя датами в SQL, исключая выходные дни - PullRequest
9 голосов
/ 30 ноября 2011

Я хотел бы создать запрос SQL, который вычисляет разницу между двумя датами, не считая выходные дни в результате.

Есть ли способ отформатировать даты, чтобы получить этот результат? Например, для базы данных Oracle:

select sysdate - creation_dttm from the_table

Ответы [ 10 ]

7 голосов
/ 13 октября 2014

Вы должны попробовать с функцией:

CREATE FUNCTION TOTAL_WEEKDAYS(date1 DATE, date2 DATE)
RETURNS INT
RETURN ABS(DATEDIFF(date2, date1)) + 1
     - ABS(DATEDIFF(ADDDATE(date2, INTERVAL 1 - DAYOFWEEK(date2) DAY),
                    ADDDATE(date1, INTERVAL 1 - DAYOFWEEK(date1) DAY))) / 7 * 2
     - (DAYOFWEEK(IF(date1 < date2, date1, date2)) = 1)
     - (DAYOFWEEK(IF(date1 > date2, date1, date2)) = 7);

Тест:

SELECT TOTAL_WEEKDAYS('2013-08-03', '2013-08-21') weekdays1,
       TOTAL_WEEKDAYS('2013-08-21', '2013-08-03') weekdays2;

Результат:

| WEEKDAYS1 | WEEKDAYS2 |
-------------------------
|        13 |        13 |
4 голосов
/ 26 марта 2016

Я нашел несколько ответов в этой теме, чтобы не делать то, что они утверждают. После некоторых экспериментов, тестирования и настройки я могу внести свой вклад.

declare @firstdate Date
declare @seconddate Date

set @firstDate = convert(date, '2016-03-07')
set @seconddate = convert(date, '2016-04-04')


select (datediff(dd, @firstDate, @secondDate)) - 
    (( DateDiff(wk, @firstDate, @secondDate) * 2) - 
      case when datepart(dw, @FirstDate) = 7 then 1 else 0 end -
      case when datepart(dw, @secondDate) = 7 then -1 else 0 end)

Включен тестовый комплект - вы можете просто настроить две даты и запустить свои собственные тесты. Предполагается, что разница между двумя соседними датами в будние дни равна 1. Если в вашей стране для обозначения выходных используются разные дни, вам нужно будет соответственно установить базу данных, чтобы ваша «суббота» составляла 7, а ваше «воскресенье» - 1.

3 голосов
/ 30 ноября 2011

Из предыдущего поста :

DECLARE @StartDate DATETIME
DECLARE @EndDate DATETIME
SET @StartDate = '2008/10/01'
SET @EndDate = '2008/10/31'


SELECT
   (DATEDIFF(dd, @StartDate, @EndDate) + 1)
  -(DATEDIFF(wk, @StartDate, @EndDate) * 2)
  -(CASE WHEN DATENAME(dw, @StartDate) = 'Sunday' THEN 1 ELSE 0 END)
  -(CASE WHEN DATENAME(dw, @EndDate) = 'Saturday' THEN 1 ELSE 0 END)
2 голосов
/ 01 декабря 2011

Я нашел другой способ вычислить разницу, используя только SQL:

select sysdate - creation_dttm
- 2 * (to_char(sysdate, 'WW') - to_char(creation_dttm, 'WW'))
from the_table
1 голос
/ 28 декабря 2012

Вот пример:
Существует четыре переменные, первые две говорят сами за себя, просто введите дату в формате ГГГГММДД, третья - установить количество рабочих дней в неделю, поэтому, если сайт работает 6 дней в неделю, установите его 6, пять дней в неделю введите 5 и т. д. Наконец, DATE_SEQ_NORML_FACTOR должен быть равен 1 при работе с Oracle. Это делается для того, чтобы юлианская дата была равна 1 в понедельник, 2 во вторник и т. Д. При применении MOD 7. Другие БД, вероятно, будут иметь разные значения от 0 до 6, поэтому проверьте их перед использованием с другими БД.

Вот ограничения: 1. Эта формула предполагает, что первый день недели - понедельник. 2. Эта формула предполагает, что все дни в течение одной недели НЕПРЕРЫВНЫ. 3. Эта формула будет работать ТОЛЬКО тогда, когда две даты, включенные в расчет, приходятся на рабочий день или рабочий день, например. «Дата начала» в СУББОТУ, когда локация работает, только Пн-Пт не будет работать.

SELECT

  &&START_DATE_YYYYMMDD "Start Date", --in YYYYMMDD format

  &&END_DATE_YYYYMMDD "End Date", --in YYYYMMDD format

  &&WK_WORK_DAY_CNT "Week Work Day Count", --Number of work day per week

  &&DATE_SEQ_NORML_FACTOR "Normalization Factor", --set to 1 when run in Oracle

  CASE

  WHEN

    FLOOR( TO_CHAR( TO_DATE( &&START_DATE_YYYYMMDD , 'YYYYMMDD') , 'J' ) + &&DATE_SEQ_NORML_FACTOR / 7 ) =

    FLOOR( TO_CHAR( TO_DATE( &&END_DATE_YYYYMMDD , 'YYYYMMDD') , 'J' ) + &&DATE_SEQ_NORML_FACTOR / 7 )

  THEN(

    TO_CHAR( TO_DATE( &&END_DATE_YYYYMMDD , 'YYYYMMDD') , 'J' ) -

    TO_CHAR( TO_DATE( &&START_DATE_YYYYMMDD , 'YYYYMMDD') , 'J' ) + 1

  )

  ELSE(

    (

      &&WK_WORK_DAY_CNT - MOD( TO_CHAR( TO_DATE( &&START_DATE_YYYYMMDD , 'YYYYMMDD') , 'J' ) + &&DATE_SEQ_NORML_FACTOR , 7 ) + 1

    ) +

    MOD( TO_CHAR( TO_DATE( &&END_DATE_YYYYMMDD , 'YYYYMMDD') , 'J' ) + &&DATE_SEQ_NORML_FACTOR , 7 ) +

    (

      (

        (

          TO_CHAR( TO_DATE( &&END_DATE_YYYYMMDD , 'YYYYMMDD') , 'J' ) -

          MOD( TO_CHAR( TO_DATE( &&END_DATE_YYYYMMDD , 'YYYYMMDD') , 'J' ) + &&DATE_SEQ_NORML_FACTOR , 7 )

        ) -

        (

          TO_CHAR( TO_DATE( &&START_DATE_YYYYMMDD , 'YYYYMMDD') , 'J' ) +

          (

            7 -

            (

              MOD( TO_CHAR( TO_DATE( &&START_DATE_YYYYMMDD , 'YYYYMMDD') , 'J' ) + &&DATE_SEQ_NORML_FACTOR , 7 )

            )

          )

        )

      ) / 7 * &&WK_WORK_DAY_CNT

    )

  ) END "Week Day Count"

FROM DUAL
0 голосов
/ 04 августа 2015

Вы можете попробовать это:

SELECT
    Id,
    DATEDIFF(d, datefrom, dateto) AS TotDays,
    DATEDIFF(wk, datefrom, dateto) AS Wkds,
    DATEDIFF(d, datefrom, dateto) - DATEDIFF(wk, datefrom, dateto) AS Days
FROM
    YOURTABLE
0 голосов
/ 07 июля 2015
  • Рассчитывает разницу в днях между двумя датами
  • Вычисляет разницу в числах недели и числах года, вычитает номера недели и затем умножает результат на 2, чтобы вычислить количество нерабочих дней между двумя датами. Если номера года отличаются, рассчитайте 52 * разницу в году + номер недели.

((sysdate - ced.created_dt) + ((((to_char(ced.created_dt,'IW') - ((to_char(sysdate,'YY') - to_char(ced.created_dt,'YY'))* 52)) - to_char(to_char(sysdate,'IW')))) * 2)) duration_in_weekdays

0 голосов
/ 27 октября 2014

Существует проблема с ответом @lightmania, я думаю.

Использование значений:

select (TO_DATE('06/02/2014', 'DD/MM/YYYY') - 
        TO_DATE('04/02/2014', 'DD/MM/YYYY') - 
        2 * (to_char(TO_DATE('06/02/2014', 'DD/MM/YYYY'), 'WW') -
             to_char(TO_DATE('04/02/2014', 'DD/MM/YYYY'), 'WW'))) from dual;

Возвращено 0 вместо 2, что должно было быть возвращено.

0 голосов
/ 23 августа 2012

Я обновил функцию @ JOpuckman, чтобы учесть, что в разных регионах не всегда выходные субботы и воскресенья. Вот код на тот случай, если кому-то еще понадобится применить это глобально;

DECLARE @FirstDate DateTime
DECLARE @SecondDate DateTime

SET @FirstDate = '08-20-2012'
SET @SecondDate = '08-24-2012'

DECLARE @range INT;
DECLARE @WeekendDayNameStart VARCHAR(50) 
DECLARE @WeekendDayNameEnd VARCHAR(50)

SET @WeekendDayNameStart = 'FRIDAY'
SET @WeekendDayNameEnd = (
    SELECT CASE @WeekendDayNameStart
        WHEN 'SUNDAY' THEN 'MONDAY'
        WHEN 'MONDAY' THEN 'TUESDAY'
        WHEN 'TUESDAY' THEN 'WEDNESDAY'
        WHEN 'WEDNESDAY' THEN 'THURSDAY'
        WHEN 'THURSDAY' THEN 'FRIDAY'
        WHEN 'FRIDAY' THEN 'SATURDAY'
        WHEN 'SATURDAY' THEN 'SUNDAY'
    END
)

DECLARE @NumWorkDays INT

SET @range = DATEDIFF(DAY, @FirstDate, @SecondDate); 
SET @NumWorkDays = (
SELECT  
@range / 7 * 5 + @range % 7 - ( 
    SELECT COUNT(*)  
    FROM ( 
        SELECT 1 AS d 
        UNION ALL SELECT 2  
        UNION ALL SELECT 3  
        UNION ALL SELECT 4  
        UNION ALL SELECT 5  
        UNION ALL SELECT 6  
        UNION ALL SELECT 7 
        ) weekdays 
    WHERE d <= @range % 7  
    AND DATENAME(WEEKDAY, @SecondDate - d) IN (@WeekendDayNameStart, @WeekendDayNameEnd))
);

-- Calculate whether the current date is a working day
DECLARE @CurDateExtra INT
SET @CurDateExtra = 
(
    CASE DATENAME(WEEKDAY, @SecondDate)
    WHEN @WeekendDayNameStart THEN 0
    WHEN @WeekendDayNameEnd THEN 0
    ELSE 1
    END
)

SET @NumWorkDays = @NumWorkDays + @CurDateExtra
SELECT @NumWorkDays
0 голосов
/ 01 декабря 2011

Мы включили следующую логику в несколько отчетов с большим успехом. Извините, я больше не помню источник этого скрипта, чтобы отдать им должное.

DECLARE @range INT;

SET @range = DATEDIFF(DAY, @FirstDate, @SecondDate); 
SET @NumWorkDays = (
    SELECT  
    @range / 7 * 5 + @range % 7 - ( 
        SELECT COUNT(*)  
        FROM ( 
            SELECT 1 AS d 
            UNION ALL SELECT 2  
            UNION ALL SELECT 3  
            UNION ALL SELECT 4  
            UNION ALL SELECT 5  
            UNION ALL SELECT 6  
            UNION ALL SELECT 7 
            ) weekdays 
        WHERE d <= @range % 7  
        AND DATENAME(WEEKDAY, @SecondDate - d) IN ('Saturday', 'Sunday'))
    );
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...