2014-10-27 3 views
2

Я искал и должен найти этот небольшой полезный фрагмент.SQL Server: получите дату с параметрами год, неделя, день недели

Я хочу, чтобы ввести ...

  • Год (2014)
  • НомерНедели (2)
  • Будни (2 = вторник, в моем случае)

Ожидаемый результат: 2014-01-07 (7 января)

И получить полную дату взамен, кто-нибудь?

EDIT: Мой сервер SQL 2008


готового кода спасибо всем !.

declare @year int = 2014 
declare @weeknr int = 2 
declare @daynroffset int = 2 


SELECT 
    DATEADD(DAY,+ (@daynroffset-1), 
    DATEADD(DAY,-DATEPART(DW,CAST('1/1/' + cast(@year as varchar) AS Date))+2,DATEADD(WK,@weeknr- 1,CAST('1/1/' + cast(@year as varchar) AS Date))) 
) 
+1

вам нужен календарную таблицу – Horaciux

+0

См http://stackoverflow.com/questions/607817/get-dates-from-a-week-number -in-t-sql – Raj

+0

SQL Server ** 2012 ** и новее имеют функцию '' GetDateFromParts' (http://msdn.microsoft.com/en-us/library/hh213228.aspx) –

ответ

0

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

DECLARE @Year INT = 2014 
DECLARE @WeekNum INT = 2 
DECLARE @WeekDay INT = 2 

SELECT 
    BaseDate = CAST(@year AS VARCHAR(4)) 
    , RoundToWeekStart = DATEADD(WEEK, DATEDIFF(WEEK, 0, CAST(@year AS VARCHAR(4))), 0) -- Will be a Monday 
    , AddWeeksToRoundedDate = DATEADD(WEEK, @WeekNum - 1, DATEADD(WEEK, DATEDIFF(WEEK, 0, CAST(@year AS VARCHAR(4))), 0)) 
    , AddWeekDay = DATEADD(DAY, @WeekDay - 1, DATEADD(WEEK, @WeekNum - 1, DATEADD(WEEK, DATEDIFF(WEEK, 0, CAST(@year AS VARCHAR(4))), 0))) 

2012+

DECLARE @Year INT = 2014 
DECLARE @WeekNum INT = 2 
DECLARE @WeekDay INT = 2 

SELECT 
    BaseDate = DATEFROMPARTS(@Year, 1, 1) 
    , RoundToWeekStart = DATEADD(WEEK, DATEDIFF(WEEK, 0, DATEFROMPARTS(@Year, 1, 1)), 0) -- Will be a Monday 
    , AddWeeksToRoundedDate = DATEADD(WEEK, @WeekNum - 1, DATEADD(WEEK, DATEDIFF(WEEK, 0, DATEFROMPARTS(@Year, 1, 1)), 0)) 
    , AddWeekDay = DATEADD(DAY, @WeekDay - 1, DATEADD(WEEK, @WeekNum - 1, DATEADD(WEEK, DATEDIFF(WEEK, 0, DATEFROMPARTS(@Year, 1, 1)), 0))) 
+0

Не работает с SQL Server 2008. 'DATEFROMPARTS' появляется в 2012 году. –

3

КОД:

2012+:
DATEADD(DAY,-DATEPART(DW,DATEFROMPARTS("YEAR",1,1))+1+"DAY OF WEEK",DATEADD(WK,"WEEK NUMBER"-1,DATEFROMPARTS(2014,1,1)))

2008+:
SELECT DATEADD(DAY,-DATEPART(DW,CAST(CONCAT('1/1/',"YEAR") AS Date))+1+"DAY OF WEEK",DATEADD(WK,"WEEK NUMBER"-1,CAST(CONCAT('1/1/',"YEAR") AS Date)))

Просто замените значения, если это необходимо.

Это будет работать в любой день.

+0

Отличный ... но не думаю, что у 2008 есть datefromparts как функция – freand

+0

Тогда вы можете подставить' CONCAT' внутри 'CAST' для этого. –

+0

Yup ... в стороне от недостающей функции concat ... думаю, что у меня есть это ... вместо этого использовали знак «+», спасибо за то, что вы меня по пути ... плохо опубликуйте результат здесь – freand

1
declare @year int = 2014 
declare @week int = 2 
declare @day int = 2 

declare @date datetime = cast(cast(@year as varchar(20)) + '-01-01' as datetime) 
declare @offset int = datepart(dw, @date) - 1 
set @date = dateadd(day, @day - @offset, dateadd(ww, @week - 1, @date)) 

print @date 
+0

Не работает с SQL Server 2008. 'DATEFROMPARTS' появляется в 2012 году. –

+0

проверять обновленный ответ – SmartDev

1

Другие ответы (до сих пор) используют механизмы по умолчанию SQL Server для определения недели и дня недели. В этом случае текущая настройка языка определяет день недели (в соответствии с настройкой @@DATEFIRST), а DATEPART(wk использует 1 января как фиксированную дату, содержащуюся на первой неделе.

Чтобы получить детерминированный ответ независимо от языкового значения, можно используйте ISO 8601 week standard, который начинается неделю по понедельникам и где первая неделя всегда содержит 4 января.

Этот код определяет дату, основанную на недели ISO:

declare @year int = 2016 
declare @isoweek int = 22 
declare @isoday int = 2 

-- ISO-WEEK 1 always contains 4th Jan, so let's use this as a base 
declare @date datetime = cast(cast(@year as varchar(4)) + '-01-04T12:00:00' as datetime) 

-- Offset the wanted DayOfWeek versus our base date 
-- We also set DATEFIRST temporarily because it affects DayOfWeek 
-- ISO-Weeks always start on Monday 
declare @datefirst int = @@DATEFIRST 
SET DATEFIRST 1 
declare @offset int = datepart(dw, @date) - 1 
SET DATEFIRST @datefirst 

-- Add given day and week to basedate 
set @date = dateadd(day, @isoday - 1 - @offset, dateadd(wk, @isoweek - 1, @date)) 

print @date 
+0

Использование 4-го янвана приятно! Спасибо, это работает! –

+0

Только одна вещь для добавления - конструкция 'cast (cast (@year as varchar (4)) + '-01-04' как datetime)' в зависимости от настроек. Это может быть не 4 JAN, а 1 APR. Остальное хорошо! –

+0

@ Андре Давыденко: Спасибо за щедрость! У меня сложилось впечатление, что использование формата 'yyyy-mm-dd' будет безопасным, но вы правы, это не так. Однако полный ISO 8601 формат должен быть безопасным, поэтому я буду соответствующим образом обновлять ответ. – TToni

Смежные вопросы