@ Микаэль Эрикссон получил замечательную идею, но его реализация кажется несколько усложненной.
Вот то, что я придумал (и я хотел бы подчеркнуть, что это основано на решение от @ Mikael , которому должен идти основной кредит):
ALTER FUNCTION dbo.f_countweekdays (@Dow int, @StartDate datetime, @EndDate datetime)
RETURNS int
AS BEGIN
RETURN (
SELECT
DATEDIFF(wk, @StartDate, @EndDate)
- CASE WHEN DATEPART(dw, @StartDate) > @Dow THEN 1 ELSE 0 END
- CASE WHEN DATEPART(dw, @EndDate) < @Dow THEN 1 ELSE 0 END
+ 1
)
END
ОБНОВЛЕНИЕ
AsМикаэль правильно отметил в ветке комментариев своего ответа, чтобы вышеуказанное решение работало правильно, для параметра DATEFIRST должно быть установлено значение 7
(воскресенье).Хотя я не смог найти это документированное, быстрый тест показал, что DATEDIFF(wk)
не учитывает фактическую настройку DATEFIRST и действительно возвращает разницу в неделях, как если бы DATEFIRST всегда был установлен на 7. В то же время DATEPART(dw)
уважает DATEFIRST
таким образом, если для параметра DATEFIRST установлено значение, отличное от 7, две функции возвращают взаимно несовместимые результаты.
Поэтому в приведенный выше сценарий необходимо внести поправки, чтобы учесть различные значения параметра DATEFIRST при расчете DATEDIFF(wk)
.К счастью, исправление, по-моему, не сделало решение намного более сложным, чем раньше, на мой взгляд.Судите сами, хотя:
ALTER FUNCTION dbo.f_countweekdays (@Dow int, @StartDate datetime, @EndDate datetime)
RETURNS int
AS BEGIN
RETURN (
SELECT
DATEDIFF(wk, DATEADD(DAY, -@@DATEFIRST, @StartDate),
DATEADD(DAY, -@@DATEFIRST, @EndDate))
- CASE WHEN DATEPART(dw, @StartDate) > @Dow THEN 1 ELSE 0 END
- CASE WHEN DATEPART(dw, @EndDate) < @Dow THEN 1 ELSE 0 END
+ 1
)
END
Отредактировано: Обе -@@DATEFIRST % 7
записи были упрощены до -@@DATEFIRST
, как кто-то предложил здесь .