Это один гораздо сложнее, чем это должно быть. Я сделал аналогичную работу, используя datename
, но только потому, что я знаю, что все системы, которые я использую, будут настроены на английском языке как язык по умолчанию. Без этого предположения вы должны использовать datepart(dw, ...
, и вам также нужно беспокоиться о SET DATEFIRST
. Я также предполагаю, что «будний день» означает «Mon, Tue, Wed, Thu, Fri» и исключая субботу и воскресенье. (Или же TFIG применяется по всему миру?)
Таким образом, прогуливаясь по моей методике, мы начнем с того, что у вас было:
DECLARE
@Date datetime
,@BOM datetime
--SET @Date = '1/4/14' -- Should return Jan 31, 2013
SET @Date = '5/4/14' -- Should return May 30, 2014 (not May 31)
SET @BOM = DATEADD(m, DATEDIFF(m, 0, @date) + 1, 0)
PRINT @BOM
Это устанавливает @BOM (начало месяца) в первый день месяц после того, что у вас есть в @Date. (Я разделил это на несколько операторов, потому что в противном случае вам придется повторять эту функцию по всему месту в коде ниже).
Далее вам нужно «вернуться» с этого дня на один, два или три дня , Если BOM - понедельник, -3 - до прошлой пятницы; если BOM - воскресенье, -2 - до пятницы; в противном случае -1 высадит вас в будний день. Основываясь на значениях, возвращаемых datepart
, нет никакого алгоритма, который я могу придумать, чтобы сгенерировать этот -1/-2/-3-распространение, поэтому я использую оператор case (я отказываюсь от процедур циклизации из-за слишком коротких ошибок для работы с базой данных).
PRINT datepart(dw, @BOM) -- To see what is is
PRINT dateadd(dd, case
when datepart(dw, @BOM) = 2 then -3
when datepart(dw, @BOM) = 1 then -2
else -1
end
,@BOM)
Увы, это работает, только если ваш экземпляр SQL настроен с настройкой «первый день недели» по умолчанию; это проверяется через PRINT @@datefirst
, где 7 (по умолчанию) = Солнце, 6 = Сб и т. д. Опять же, ни один из возможных алгоритмов не предлагает себя, а деловая ситуация превращается в беспорядок:
PRINT dateadd(dd, case
when @@datefirst = 7 and datepart(dw, @BOM) = 2 then -3
when @@datefirst = 7 and datepart(dw, @BOM) = 1 then -2
when @@datefirst = 6 and datepart(dw, @BOM) = 3 then -3
when @@datefirst = 6 and datepart(dw, @BOM) = 2 then -2
when @@datefirst = 5 and datepart(dw, @BOM) = 4 then -3
when @@datefirst = 5 and datepart(dw, @BOM) = 3 then -2
when @@datefirst = 4 and datepart(dw, @BOM) = 5 then -3
when @@datefirst = 4 and datepart(dw, @BOM) = 4 then -2
when @@datefirst = 3 and datepart(dw, @BOM) = 6 then -3
when @@datefirst = 3 and datepart(dw, @BOM) = 5 then -2
when @@datefirst = 2 and datepart(dw, @BOM) = 7 then -3
when @@datefirst = 2 and datepart(dw, @BOM) = 6 then -2
when @@datefirst = 1 and datepart(dw, @BOM) = 1 then -3
when @@datefirst = 1 and datepart(dw, @BOM) = 7 then -2
else -1
end
,@BOM)
Уродливое, что ли? И для этого нужно учитывать и петлевые структуры.Конечно, если вы можете рассчитывать на всегда иметь один и тот же язык, на ваших экземпляров SQL, это то, что гораздо проще:
PRINT dateadd(dd, case
when datename(dw, @BOM) = 'Monday' then -3
when datename(dw, @BOM) = 'Sunday' then -2
else -1
end
,@BOM)
Любые или все вышеперечисленное может и должно быть «сцеплены вниз» в одном заявлении или запросе (или, лучше, функция); если вы можете смело делать предположения относительно языка установки и/или первого дня недели, вы можете сократить его еще больше.
это забавно, что верхняя родственный http://stackoverflow.com/questions/60174/how-can- i-prevent-sql-injection-in-php? rq = 1 –