Створіть дату з дня місяця та року за допомогою T-SQL


264

Я намагаюся перетворити дату з окремими частинами, такими як 12, 1, 2007, у час дат у SQL Server 2005. Я спробував таке:

CAST(DATEPART(year, DATE)+'-'+ DATEPART(month, DATE) +'-'+ DATEPART(day, DATE) AS DATETIME)

але це призводить до неправильної дати. Який правильний спосіб перетворити три значення дати у відповідний формат дати.


8
Будь ласка, подумайте про зміну прийнятої відповіді weblogs.sqlteam.com/jeffs/archive/2007/09/10/…
Brian Webster

ДАТЕФРОМАРТ (рік, місяць, день)
Кейт

Відповіді:


174

Припустимо y, m, d, що все int, як щодо:

CAST(CAST(y AS varchar) + '-' + CAST(m AS varchar) + '-' + CAST(d AS varchar) AS DATETIME)

Перегляньте іншу відповідь для SQL Server 2012 і вище


Поганий. Складіть мене з ints дата 1 січня 0001
Олег Док

24
Олег SQL Server DateTime не йде далі назад, ніж 1753-01-01 щось.
CodeMonkey

2
Ця відповідь залежить від параметрів формату дати, які залежать від регіональних налаштувань вашого сервера, якщо ви не вказуєте. yyyymmddФормат працює незалежно від цих параметрів. "Шість-або восьмизначний рядок завжди інтерпретується як ymd ." docs.microsoft.com/en-us/sql/t-sql/data-types/… Дивіться цю відповідь: stackoverflow.com/a/46064419/2266979
Райлі Майор

339

Спробуйте це:

Declare @DayOfMonth TinyInt Set @DayOfMonth = 13
Declare @Month TinyInt Set @Month = 6
Declare @Year Integer Set @Year = 2006
-- ------------------------------------
Select DateAdd(day, @DayOfMonth - 1, 
          DateAdd(month, @Month - 1, 
              DateAdd(Year, @Year-1900, 0)))

Це добре працює, додає перевагу не робити жодних перетворень рядків, тому це чиста арифметична обробка (дуже швидка), і це не залежить від будь-якого формату дати. значення частини, перша частина якої є цілим числом, що представляє кількість днів з 1 січня 1900 року, а друга частина - десятковий дріб, що представляє дробову частину одного дня (за час) --- Отже ціле число 0 (нуль ) завжди перекладається безпосередньо в півночі 1 січня 1900 року ...

або, завдяки пропозиції від @brinary,

Select DateAdd(yy, @Year-1900,  
       DateAdd(m,  @Month - 1, @DayOfMonth - 1)) 

Відредаговано в жовтні 2014 року. Як зазначає @cade Roux, тепер у SQL 2012 є вбудована функція:
DATEFROMPARTS(year, month, day)
це робить те ж саме.

Відредаговано 3 жовтня 2016 р. (Спасибі @bambams за те, що помітили це, та @brinary за його виправлення), останнє рішення, запропоноване @brinary. не працює у високосні роки, якщо спочатку не виконано додавання років

select dateadd(month, @Month - 1, 
     dateadd(year, @Year-1900, @DayOfMonth - 1)); 

36
@Brandon, слід позначити це як цю відповідь. Це найкращий. Зробіть це як послугу для інших читачів StackOverflow.
Білл Паетке

3
Працює у високосні роки: виберіть дату (мм, (@ y-1900) * 12 + @m - 1,0) + (@ d-1)
приховано

8
Результати мають дійсне, але помилкове значення дати, коли передається недійсна комбінація значень, наприклад @Year = 2001, @Month = 13і @DayOfMonth = 32призводить до 2002-02-01T00:00:00.000. Прийнята відповідь (від Кейда Ру) породжує помилку, яка є кориснішою.
onedaywhen

6
Не потрібно починати з нуля і додавати дні. Ви можете почати безпосередньо з @ DayOfMonth-1, а потім додати місяці та роки. Це один менший DateAdd ()!
бріанарій

2
моя голова все ще крутиться - насправді немає охайного способу це зробити? (Мені доводиться виправляти запит у SQL Server 2005)
Peter Perháč

241

SQL Server 2012 має чудову і довгоочікувану нову функцію DATEFROMPARTS (яка призведе до помилки, якщо дата недійсна - моє основне заперечення проти рішення цієї проблеми на основі DATEADD):

http://msdn.microsoft.com/en-us/library/hh213228.aspx

DATEFROMPARTS(ycolumn, mcolumn, dcolumn)

або

DATEFROMPARTS(@y, @m, @d)

11
Крім того, посилаючись на оригінальне запитання, де згадувався об’єкт Datetime, існує також функція DATETIMEFROMPARTS: msdn.microsoft.com/pl-pl/library/hh213233%28v=sql.110%29.aspx
Maciej Jaśniaczyk

116

Або використовуючи лише одну функцію додавання дат:

DECLARE @day int, @month int, @year int
SELECT @day = 4, @month = 3, @year = 2011

SELECT dateadd(mm, (@year - 1900) * 12 + @month - 1 , @day - 1)

4
найкраща відповідь ІМО. Має всі переваги відповіді Чарльза і набагато коротше.
Майкл

1
Це, безумовно, найчистіше і найпростіше. І це не видає помилку, коли значення дня також виходять за межі діапазону. Якщо залежно від обставини, може виникнути помилка, тому просто пам’ятайте, що це замовчує значення дня та місяця, які виходять за рамки очікуваного діапазону.
Шон Ковач

16

Sql Server 2012 має функцію, яка створить дату на основі частин ( DATEFROMPARTS ). Для решти нас тут створена функція db, яка визначить дату з частин (дякую @Charles) ...

IF EXISTS (SELECT * FROM dbo.sysobjects WHERE id = object_id(N'[dbo].[func_DateFromParts]'))
    DROP FUNCTION [dbo].[func_DateFromParts]
GO

CREATE FUNCTION [dbo].[func_DateFromParts]
(
    @Year INT,
    @Month INT,
    @DayOfMonth INT,
    @Hour INT = 0,  -- based on 24 hour clock (add 12 for PM :)
    @Min INT = 0,
    @Sec INT = 0
)
RETURNS DATETIME
AS
BEGIN

    RETURN DATEADD(second, @Sec, 
            DATEADD(minute, @Min, 
            DATEADD(hour, @Hour,
            DATEADD(day, @DayOfMonth - 1, 
            DATEADD(month, @Month - 1, 
            DATEADD(Year, @Year-1900, 0))))))

END

GO

Ви можете назвати це так ...

SELECT dbo.func_DateFromParts(2013, 10, 4, 15, 50, DEFAULT)

Повертається ...

2013-10-04 15:50:00.000

12

Спробуйте CONVERT замість CAST.

CONVERT дозволяє третій параметр, що вказує формат дати.

Список форматів тут: http://msdn.microsoft.com/en-us/library/ms187928.aspx

Оновити після вибору іншої відповіді як "правильної" відповіді:

Я не дуже розумію, чому вибирається відповідь, яка явно залежить від налаштувань NLS на вашому сервері, не вказуючи на це обмеження.


Погодьтеся, формат повинен бути кваліфікованим, наприклад CONVERT (datetime2, CAST (@year AS varchar) + '.' + CAST (@ month AS varchar) + '.' + CAST (@day AS varchar), 102)
Tony Wall

9

Ви також можете використовувати

select DATEFROMPARTS(year, month, day) as ColDate, Col2, Col3 
From MyTable Where DATEFROMPARTS(year, month, day) Between @DateIni and @DateEnd

Працює в SQL з версії 2012 та AzureSQL


6

Безпечніше і акуратніше використовувати явну вихідну точку "19000101"

create function dbo.fnDateTime2FromParts(@Year int, @Month int, @Day int, @Hour int, @Minute int, @Second int, @Nanosecond int)
returns datetime2
as
begin
    -- Note! SQL Server 2012 includes datetime2fromparts() function
    declare @output datetime2 = '19000101'
    set @output = dateadd(year      , @Year - 1900  , @output)
    set @output = dateadd(month     , @Month - 1    , @output)
    set @output = dateadd(day       , @Day - 1      , @output)
    set @output = dateadd(hour      , @Hour         , @output)
    set @output = dateadd(minute    , @Minute       , @output)
    set @output = dateadd(second    , @Second       , @output)
    set @output = dateadd(ns        , @Nanosecond   , @output)
    return @output
end

Чому б не використовувати просто, declare @output datetime2 = 0а не @Year - 1900використовувати @Year - DATEPART(year,0);? Це працює без будь-яких закидів у SQL Server 2008 та набагато зрозуміліше.
tsionyx

Тому що це не спрацює. Не можна призначати 0 до datetime2. Ваш код поверне "Сутичка типу Операнда: int несумісний з datetime2"
Джек

4

Якщо ви не хочете тримати з нього рядки, це також працює (Введіть його у функцію):

DECLARE @Day int, @Month int, @Year int
SELECT @Day = 1, @Month = 2, @Year = 2008

SELECT DateAdd(dd, @Day-1, DateAdd(mm, @Month -1, DateAdd(yy, @Year - 2000, '20000101')))

4

Я додаю однолінійне рішення, якщо вам потрібен час від дати та часу :

select dateadd(month, (@Year -1900)*12 + @Month -1, @DayOfMonth -1) + dateadd(ss, @Hour*3600 + @Minute*60 + @Second, 0) + dateadd(ms, @Millisecond, 0)


2

Для версій SQL Server нижче 12 я можу рекомендувати використовувати CASTв поєднанні зSET DATEFORMAT

-- 26 February 2015
SET DATEFORMAT dmy
SELECT CAST('26-2-2015' AS DATE)

SET DATEFORMAT ymd
SELECT CAST('2015-2-26' AS DATE)

як ви створюєте ці рядки, залежить від вас


1

Спробуйте цей запит:

    SELECT SUBSTRING(CONVERT(VARCHAR,JOINGDATE,103),7,4)AS
    YEAR,SUBSTRING(CONVERT(VARCHAR,JOINGDATE,100),1,2)AS
MONTH,SUBSTRING(CONVERT(VARCHAR,JOINGDATE,100),4,3)AS DATE FROM EMPLOYEE1

Результат:

2014    Ja    1
2015    Ja    1
2014    Ja    1
2015    Ja    1
2012    Ja    1
2010    Ja    1
2015    Ja    1

1

Я знаю, що ОП просить відповісти на SQL 2005, але питання досить старе, тому якщо ви працюєте з SQL 2012 або вище, ви можете використовувати наступне:

SELECT DATEADD(DAY, 1, EOMONTH(@somedate, -1))

Довідка: https://docs.microsoft.com/en-us/sql/t-sql/functions/eomonth-transact-sql?view=sql-server-2017&viewFallbackFrom=sql-server-previousversions


0

Я особисто віддаю перевагу підрядковій стрічці, оскільки вона надає варіанти очищення та можливість розділити рядок за потребою. Припущення полягає в тому, що дані мають формат 'dd, mm, yyyy'.

--2012 and above
SELECT CONCAT (
        RIGHT(REPLACE(@date, ' ', ''), 4)
        ,'-'
        ,RIGHT(CONCAT('00',SUBSTRING(REPLACE(@date, ' ', ''), CHARINDEX(',', REPLACE(@date, ' ', '')) + 1, LEN(REPLACE(@date, ' ', '')) - CHARINDEX(',', REPLACE(@date, ' ', '')) - 5)),2)
        ,'-'
        ,RIGHT(CONCAT('00',SUBSTRING(REPLACE(@date, ' ', ''), 1, CHARINDEX(',', REPLACE(@date, ' ', '')) - 1)),2)
        )

--2008 and below
SELECT   RIGHT(REPLACE(@date, ' ', ''), 4)
        +'-'
        +RIGHT('00'+SUBSTRING(REPLACE(@date, ' ', ''), CHARINDEX(',', REPLACE(@date, ' ', '')) + 1, LEN(REPLACE(@date, ' ', '')) - CHARINDEX(',', REPLACE(@date, ' ', '')) - 5),2)
        +'-'
        +RIGHT('00'+SUBSTRING(REPLACE(@date, ' ', ''), 1, CHARINDEX(',', REPLACE(@date, ' ', '')) - 1),2)

Ось демонстрація того, як можна подати до суду, якщо дані зберігаються у стовпці. Потрібно сказати, що ідеально перевірити набір результатів перед тим, як подати заявку на стовпець

DECLARE @Table TABLE (ID INT IDENTITY(1000,1), DateString VARCHAR(50), DateColumn DATE)

INSERT INTO @Table
SELECT'12, 1, 2007',NULL
UNION
SELECT'15,3, 2007',NULL
UNION
SELECT'18, 11 , 2007',NULL
UNION
SELECT'22 , 11, 2007',NULL
UNION
SELECT'30, 12, 2007  ',NULL

UPDATE @Table
SET DateColumn = CONCAT (
        RIGHT(REPLACE(DateString, ' ', ''), 4)
        ,'-'
        ,RIGHT(CONCAT('00',SUBSTRING(REPLACE(DateString, ' ', ''), CHARINDEX(',', REPLACE(DateString, ' ', '')) + 1, LEN(REPLACE(DateString, ' ', '')) - CHARINDEX(',', REPLACE(DateString, ' ', '')) - 5)),2)
        ,'-'
        ,RIGHT(CONCAT('00',SUBSTRING(REPLACE(DateString, ' ', ''), 1, CHARINDEX(',', REPLACE(DateString, ' ', '')) - 1)),2)
        ) 

SELECT ID,DateString,DateColumn
FROM @Table
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.