Создать дату из месяца, месяца и года с помощью T-SQL

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

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

но это приводит к неправильной дате. Каков правильный способ превратить три значения даты в правильный формат даты и времени.

Ответ 1

Предполагая y, m, d все int, как насчет:

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

См. мой другой ответ для SQL Server 2012 и выше

Ответ 2

Попробуйте следующее:

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)))

Он работает так же, добавил преимущество не делать каких-либо преобразований строк, поэтому он выполняет чистую арифметическую обработку (очень быстро) и не зависит от формата даты Это основывается на том, что внутреннее представление SQL Server для значений datetime и smalldatetime является значением из двух частей, первая часть которого представляет собой целое число, представляющее количество дней с 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)); 

Ответ 3

В SQL Server 2012 есть замечательная и долгожданная новая функция DATEFROMPARTS (что приведет к ошибке, если дата недействительна - мое основное возражение против решения DATEADD для этой проблемы):

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

DATEFROMPARTS(ycolumn, mcolumn, dcolumn)

или

DATEFROMPARTS(@y, @m, @d)

Ответ 4

Или используя только одну функцию dateadd:

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

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

Ответ 5

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

Ответ 6

Попробуйте CONVERT вместо CAST.

CONVERT разрешает третий параметр, указывающий формат даты.

Список форматов находится здесь: http://msdn.microsoft.com/en-us/library/ms187928.aspx

Обновление после того, как в качестве "правильного" ответа был выбран другой ответ:

Я не понимаю, почему выбран ответ, который явно зависит от настроек NLS на вашем сервере, без указания этого ограничения.

Ответ 7

Вы также можете использовать

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

Работает в SQL с ver.2012 и AzureSQL

Ответ 8

Более безопасно и аккуратно использовать явную начальную точку "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

Ответ 9

Если вы не хотите, чтобы строки были из него, это тоже работает (поместите его в функцию):

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')))

Ответ 10

Я добавляю однострочное решение, если вам нужна дата и время из частей даты и времени:

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

Ответ 11

Попробуйте

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

Ответ 12

Для версий 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)

как вы создаете эти строки, зависит от вас

Ответ 13

Попробуйте этот запрос:

    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

Ответ 15

Я лично предпочитаю подстроку, поскольку она предоставляет параметры очистки и возможность разбивать строку по мере необходимости. Предполагается, что данные имеют формат "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