Как получить предыдущий рабочий день за неделю с текущим рабочим днем с использованием SQL-сервера
У меня есть пакет ssis, который работает в рабочие дни (пн-пт). если я получаю файл во вторник, фон (БД), он принимает дату предыдущего рабочего дня и выполняет некоторые транзакции. Если я запускаю задание в пятницу, он должен получить дату понедельника и обработать транзакции.
Я использовал приведенный ниже запрос для получения предыдущей бизнес-даты.
Select Convert(varchar(50), Position_ID) as Position_ID,
TransAmount_Base,
Insert_Date as InsertDate
from tblsample
Where AsOfdate = Dateadd(dd, -1, Convert(datetime, Convert(varchar(10), '03/28/2012', 101), 120))
Order By Position_ID
Если я выполню этот запрос, я получу результаты вчерашних Transactios. если бы я запустил тот же запрос в понедельник, он должен получить транзакции по пятницам вместо воскресений.
Ответы
Ответ 1
SELECT DATEADD(DAY, CASE DATENAME(WEEKDAY, GETDATE())
WHEN 'Sunday' THEN -2
WHEN 'Monday' THEN -3
ELSE -1 END, DATEDIFF(DAY, 0, GETDATE()))
Я предпочитаю использовать DATENAME
для таких вещей более чем через DATEPART
, поскольку он устраняет необходимость в настройке DATEFIRST
и гарантирует, что изменения в настройках времени и даты на локальных машинах не влияют на результаты. Наконец DATEDIFF(DAY, 0, GETDATE())
удалит временную часть GETDATE()
, удалив необходимость конвертировать в varchar (гораздо медленнее).
EDIT (почти 2 года)
Этот ответ был очень ранним в моей карьере SO, и он меня раздражает каждый раз, когда он получает поддержку, потому что я больше не согласен с тем, что я использую DATENAME.
Решением проблемы с маслом будет гораздо больше:
SELECT DATEADD(DAY, CASE (DATEPART(WEEKDAY, GETDATE()) + @@DATEFIRST) % 7
WHEN 1 THEN -2
WHEN 2 THEN -3
ELSE -1
END, DATEDIFF(DAY, 0, GETDATE()));
Это будет работать для всех языков и настроек DATEFIRST.
Ответ 2
Тогда как насчет:
declare @dt datetime='1 dec 2012'
select case when [email protected]@DATEFIRST=DATEPART(dw,@dt)
then DATEADD(d,-2,@dt)
when ([email protected]@DATEFIRST)%7=DATEPART(dw,@dt)%7
then DATEADD(d,-3,@dt)
else DATEADD(d,-1,@dt)
end
Ответ 3
Простейшим решением для поиска предыдущего рабочего дня является использование таблицы календаря с столбцом IsBusinessDay
или что-то подобное. Ваш запрос выглядит примерно так:
select max(BaseDate)
from dbo.Calendar c
where c.IsBusinessDay = 0x1 and c.BaseDate < @InputDate
Проблема с использованием функций заключается в том, что когда (не если) вы должны создавать исключения по любой причине (национальные праздники и т.д.), код быстро становится недостижимым; с таблицей вы просто UPDATE
одно значение. Таблица также упрощает ответы на такие вопросы, как "сколько рабочих дней существует между датами X и Y", которые довольно часто встречаются в задачах отчетности.
Ответ 4
Вы можете легко сделать это вызовом функции, добавив второй параметр, чтобы заменить GetDate() любой желаемой датой.
Он будет работать в любой день недели, в любом диапазоне дат, если вы измените GetDate().
Он не изменит дату, если день недели является датой ввода (GetDate())
Declare @DayOfWeek As Integer = 2 -- Monday
Select DateAdd(Day, ((DatePart(dw,GetDate()) + (7 - @DayOfWeek)) * -1) % 7, Convert(Date,GetDate()))
Ответ 5
Эта функция возвращает последний рабочий день и учитывает праздничные и выходные дни. Вам нужно будет создать простой праздничный стол.
-- =============================================
-- Author: Dale Kilian
-- Create date: 2019-04-29
-- Description: recursive function returns last work day for weekends and
-- holidays
-- =============================================
ALTER FUNCTION dbo.fnGetWorkWeekday
(
@theDate DATE
)
RETURNS DATE
AS
BEGIN
DECLARE @importDate DATE = @theDate
DECLARE @returnDate DATE
--Holidays
IF EXISTS(SELECT 1 FROM dbo.Holidays WHERE isDeleted = 0 AND @theDate = Holiday_Date)
BEGIN
SET @importDate = DATEADD(DAY,-1,@theDate);
SET @importDate = (SELECT dbo.fnGetWorkWeekday(@importDate))
END
--Satruday
IF(DATEPART(WEEKDAY,@theDate) = 7)
BEGIN
SET @importDate = DATEADD(DAY,-1,@theDate);
SET @importDate = (SELECT dbo.fnGetWorkWeekday(@importDate))
END
--Sunday
IF(DATEPART(WEEKDAY,@theDate) = 1)
BEGIN
SET @importDate = DATEADD(DAY,-2,@theDate);
SET @importDate = (SELECT dbo.fnGetWorkWeekday(@importDate))
END
RETURN @importDate;
END
GO
Ответ 6
select
dateadd(dd,
case DATEPART(dw, getdate())
when 1
then -2
when 2
then -3
else -1
end, GETDATE())
Ответ 7
спасибо за советы выше, у меня был небольшой вариант в запросе, поскольку мой пользователь нуждался во всех значениях для предыдущей даты. Например, сегодня понедельник, поэтому ему нужно все, начиная с прошлой пятницы в полночь до субботы в полночь. Я сделал это, используя комбо из вышеперечисленного и "между", только если кто-то заинтересован. Я не массивный техник.
-- Declare a variable for the start and end dates.
declare @StartDate as datetime
declare @EndDate as datetime
SELECT @StartDate = DATEADD(DAY, CASE DATENAME(WEEKDAY, GETDATE())
WHEN 'Sunday' THEN -2
WHEN 'Monday' THEN -3
ELSE -1 END, DATEDIFF(DAY, 0, GETDATE()))
select @EndDate = @StartDate + 1
select @StartDate , @EndDate
-- Later on in the query use "between"
and mydate between @StartDate and @EndDate
Ответ 8
Более элегантный:
select DATEADD(DAY,
CASE when datepart (dw,Getdate()) < 3 then datepart (dw,Getdate()) * -1 + -1 ELSE -1 END,
cast(GETDATE() as date))