Рассчитать рабочие дни - с понедельника по пятницу в ЦКЛ - PullRequest
1 голос
/ 25 июля 2011

Как я могу рассчитать последние пять рабочих дней, с понедельника по пятницу.мой текущий сценарий получает дату последнего понедельника, но я не могу получить дату последней пятницы.Пожалуйста, помогите

declare @StartDate datetime
declare @EndDate datetime


--Calculate date range for report

select @EndDate = Cast(convert(char(10), getdate(), 101)+' 00:00:00' as datetime)
select @StartDate = DateAdd(d, -7, @EndDate)
select @EndDate = Cast(convert(char(10), getdate(), 101)+' 23:59:59' as datetime)

select @StartDate startdate
select @EndDate  enddate

Ответы [ 6 ]

2 голосов
/ 25 июля 2011

Datepart предлагает вам простой способ получить день недели:

 SET DATEFIRST 1  -- monday is first day of the week
 SELECT DATEPART(weekday, '20110725')
 -- result is 1

См. Функции даты T-SQL и SET DATEFIRST для получения дополнительной информации.

Используя день недели, вы можете определить, сколько дней назад было в прошлый понедельник и пятницу, и использовать AddDate (как вы делаете сейчас), чтобы рассчитать их.

Обратите внимание, что вы действительно должны использовать DATEDIFF для этого типа выбора диапазона дат.Если вы выберете все до 23:59:59, всегда есть вероятность, что некоторые записи будут опущены.Например, 23: 59: 59.001 находится вне диапазона, но все еще в тот же день.С DATEDIFF вы можете проверить, находится ли он в тот же день, отбрасывая часть времени.Не нужно беспокоиться о приведении к строке, добавлении времени и отбрасывании.

1 голос
/ 26 июля 2011

Ответ более сложный, чем предполагают люди. Вам нужно вернуться на 5 дней назад и найти первый понедельник до этого и первую пятницу после этого. Для этого вы можете использовать @@ datefirst, расчет или «установить первую дату 1». Я предпочитаю не использовать последний, потому что это не может быть сделано в функциях. Как видите, я использовал расчет, @@ datefirst также хорош.

Предполагая, что вы хотите, чтобы последняя группа с понедельника по пятницу была в прошлом. Этот запрос получит это. Если вы доверяете своему текущему понедельнику, вы можете просто добавить 5 дней и вычесть 1 минуту (я бы не стал доверять, он вернется только в последний понедельник, если вы выполните запрос в понедельник).

В моем sql я не стремлюсь к простоте, я стремлюсь к эффективности.

DECLARE @getdate datetime = dateadd(day, cast(getdate() as int), 0)
-- the 'Declare' can also be written like this thanks to @Andriy M
--DECLARE @getdate = CAST(GETDATE() - 0.5 AS int)
SELECT @getdate - 5 - CAST(@getdate- 5 as int) % 7 monday,
dateadd(minute, -1, @getdate) - CAST(@getdate- 5 as int) % 7 friday

Результат:

Monday              Friday
2011-07-18 0:00:00  2011-07-22 23:59:00

* Первое решение было выходным. @AndriyM указал на это, оно было решено.


Ответ @Andriy M

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

select cast(dateadd(day, cast(getdate() as int) - .5, 0) as datetime),
cast(dateadd(day, cast(getdate() as int), 0) as datetime),
cast(dateadd(day, cast(getdate() as int) + .5, 0) as datetime)

утром последние 2 поля имеют одинаковое значение, вечером первые 2 поля имеют одинаковое значение. Я так же удивлен, как и вы, я хотел бы объяснить это. Это было проверено здесь http://data.stackexchange.com/stackoverflow/query/new

0 голосов
/ 23 января 2015

Я тоже брошу свою шляпу на ринг. : -)

DECLARE @Date      datetime = '01/11/2015'
DECLARE @StartDate datetime = DATEADD(d, (1 - (DATEDIFF(d, CAST('1899.12.31' AS datetime), @Date - 6) % 7)), @Date - 6) -- MONDAY
DECLARE @EndDate   datetime = DATEADD(d, (5 - (DATEDIFF(d, CAST('1899.12.31' AS datetime), @Date - 6) % 7)), @Date - 6) -- FRIDAY

      SELECT '@Date'      as Variable ,CONVERT(date, @Date)      as DateValue ,DATENAME(dw, @Date)      as DayOfTheWeek
UNION SELECT '@StartDate' as Variable ,CONVERT(date, @StartDate) as DateValue ,DATENAME(dw, @StartDate) as DayOfTheWeek
UNION SELECT '@EndDate'   as Variable ,CONVERT(date, @EndDate)   as DateValue ,DATENAME(dw, @EndDate)   as DayOfTheWeek

-- Variable    DateValue   DayOfTheWeek
-- ----------  ----------  ------------
-- @Date       2015-01-11  Sunday
-- @StartDate  2015-01-05  Monday
-- @EndDate    2015-01-09  Friday

БОНУС: Здесь вы можете создать быстрый стол из 5 рабочих дней, используя ту же технику.

SELECT DATENAME(dw, DATEADD(d, TT.DaysToAdd, DATEADD(d, (1 - (DATEDIFF(d, CAST('1899.12.31' AS datetime), @Date - 6) % 7)), @Date - 6))) as DayOfTheWeek
      ,             DATEADD(d, TT.DaysToAdd, DATEADD(d, (1 - (DATEDIFF(d, CAST('1899.12.31' AS datetime), @Date - 6) % 7)), @Date - 6))  as DateValue
  FROM (SELECT ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) - 1 as DaysToAdd FROM (VALUES(0),(0),(0),(0),(0)) a(n)) as TT

-- DayOfTheWeek                   DateValue
-- ------------------------------ -----------------------
-- Monday                         2015-01-05 00:00:00.000
-- Tuesday                        2015-01-06 00:00:00.000
-- Wednesday                      2015-01-07 00:00:00.000
-- Thursday                       2015-01-08 00:00:00.000
-- Friday                         2015-01-09 00:00:00.000

Вот объяснение:

1) Сначала нам нужно узнать, с какой даты начать нашу оценку. Для этого примера мы решили использовать воскресенье, 11 января 2015 года.

DECLARE @Date2 datetime = '01/11/2015'

1b) Приятно иметь бонусную технику для получения названия дня недели с учетом значения даты

SELECT @Date2 as DateValue, DATENAME(dw, @Date2) as DayOfTheWeek

2) Затем нам нужно детерминистически (по американскому календарю) узнать, какой день недели численно находится между 1 и 7

  • ПРИМЕЧАНИЕ. 1899.12.31 - это первое воскресенье до 1900.01.01, которое является МИНИМАЛЬНЫМ значением для типа данных SmallDateTime.
  • ПРИМЕЧАНИЕ: Да, вы можете использовать DATEPART (dw, @Date), как это проще, но это не является детерминированным, учитывая, что определенные серверные среды могут иметь разные конфигурации
  • РЕЗУЛЬТАТЫ: 1 = воскресенье | 2 = понедельник | 3 = вторник | 4 = среда | 5 = четверг | 6 = пятница | 7 = суббота

    SELECT ((DATEDIFF(d, CAST('1899.12.31' AS datetime), @Date2) % 7) + 1) [DayOfWeek Deterministic (Based on US)]
    

3) Теперь, учитывая любую дату, вы должны иметь детерминистский способ определения понедельника для данной недели

SELECT DATEADD(d, (1 - (DATEDIFF(d, CAST('1899.12.31' AS datetime), @Date2) % 7)), @Date2) as [Monday Day of the Week - Deterministic (Based on US)]

4) Теперь, учитывая любую дату, вы должны иметь детерминистический способ определения пятницы для данной недели

SELECT DATEADD(d, (5 - (DATEDIFF(d, CAST('1899.12.31' AS datetime), @Date2) % 7)), @Date2) as [Monday Day of the Week - Deterministic (Based on US)]

5) Последний метод манипулирования датами, который нам нужен, - это знать, как попасть в неделю, в которой первая полная неделя будних дней происходит раньше. Например, если мы находимся в воскресенье и вычитаем из него 1 день, то мы попадаем в субботу, которая ставит нас на предыдущую неделю, которая является первой полной неделей в будние дни. В качестве альтернативы, если мы также вычтем 1 день из понедельника, это приведет нас только к воскресенью, которое не является предыдущей неделей, поэтому вычитания 1 дня недостаточно. С другой стороны, если бы мы были в субботу и вычли 7 дней, это перенесло бы нас за предыдущую полную неделю буднего на предыдущую неделю, что слишком далеко. Вот краткий анализ, чтобы выяснить, какие магические числа вы можете вычесть, которые будут работать с любым днем ​​недели. Как вы можете видеть ниже, магическое число - 6.

--                                            DAYS TO SUBTRACT
-- Day of the Week      - 0     - 1     - 2     - 3     - 4     - 5     - 6     - 7
-- ===============      ====    ====    ====    ====    ====    ====    ====    ====
-- Sunday               Bad     Good    Good    Good    Good    Good    Good    Good
-- Monday               Bad     Bad     Good    Good    Good    Good    Good    Good
-- Tuesday              Bad     Bad     Bad     Good    Good    Good    Good    Good
-- Wednesday            Bad     Bad     Bad     Bad     Good    Good    Good    Good
-- Thursday             Bad     Bad     Bad     Bad     Bad     Good    Good    Good
-- Friday               Bad     Bad     Bad     Bad     Bad     Bad     Good    Good
-- Saturday             Good    Good    Good    Good    Good    Good    Good    Bad

БОНУС) Если вы хотите, чтобы все рабочие дни были в маленьком столике, то вам также следует использовать "таблицу подсчета", основанную на быстром нулевом значении. Есть много способов сделать это, поэтому выберите свой вкус. Вот несколько.

SELECT * FROM (SELECT 0 as DaysToAdd UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4) as TT
SELECT * FROM (SELECT TOP 5 ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) - 1 as DaysToAdd FROM sys.all_columns a CROSS JOIN sys.all_columns b) as TT
SELECT * FROM (SELECT ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) - 1 as DaysToAdd FROM (VALUES(0),(0),(0),(0),(0)) a(n)) as TT
0 голосов
/ 18 сентября 2012
DECLARE @my int
DECLARE @myDeduct int
DECLARE @day INT
DECLARE @mydate DATETIME

SET @mydate = '2012-08-01'

SET @myDeduct = 0
SET DateFirst 1 -- Set it monday=1 (value)

--Saturday and Sunday on the first and last day of a month will Deduct 1
IF (DATEPART(weekday,(DATEADD(dd,-(DAY(@mydate)-1),@mydate))) > 5)
SET @myDeduct = @myDeduct + 1

IF (DATEPART(weekday,(DATEADD(dd,-(DAY(DATEADD(mm,1,@mydate))),DATEADD(mm,1,@mydate)))) > 5)
SET @myDeduct = @myDeduct + 1

SET @my = day(DATEADD(dd,-(DAY(DATEADD(mm,1,@mydate))),DATEADD(mm,1,@mydate)))

select (((@my/7) * 5 + (@my%7)) - @myDeduct) as Working_Day_per_month
0 голосов
/ 26 июля 2011

Это все относительно даты СЕГОДНЯ, верно?

Итак, выясните, что сегодня такое DATEPART(weekday, getdate())

И затем превратите это в переменную корректировки - например:

declare @adjustment int
set @adjustment = CASE DATEPART(weekday, getdate()) WHEN 'MONDAY' THEN 0 WHEN 'TUESDAY' THEN 1, ...END

Итак, понедельник, который вы хотите, был бы сегодня - 7 - @adjustment... и пятница, которую вы хотите, будет понедельник + 5

Declare @myMonday smalldatetime,
        @myFriday smalldatetime
set @myMonday = getdate() - 7 - @adjustment
set @myFriday = @myMonday + 5
0 голосов
/ 25 июля 2011

Эти два вопроса:

может помочь.

Хотя, если вы уже знаете, как найти последний понедельник, вы можете легко найти соответствующийПятница, добавив 4 дня к дате понедельника с помощью функции DATEADD().Например:

SELECT @EndDate = DATEADD(DAY, 4, @StartDate)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...