使用T-SQL从日期月份和年份中创建日期


264

我正在尝试将包含2007年12月1日等各个部分的日期转换为SQL Server 2005中的日期时间。我尝试了以下方法:

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

但这会导致日期错误。将三个日期值转换为正确的日期时间格式的正确方法是什么?



DATEFROMPARTS(年,月,日)
凯特

Answers:


174

假设y, m, d全部int,如何:

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

请参阅针对SQL Server 2012及更高版本的其他答案


不好 从ints撰写我的时间为0001
Oleg Dok 2013年

24
Oleg SQL Server DateTime不要再追溯到1753-01-01了。
CodeMonkey

2
此答案取决于日期格式设置,如果未指定,则取决于服务器的区域设置。该yyyymmdd格式的作品不管这些设置。“六位数或八位数的字符串始终被解释为ymd。” docs.microsoft.com/zh-CN/sql/t-sql/data-types/… 看到此答案:stackoverflow.com/a/46064419/2266979
Riley Major

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

它也可以正常工作,并且增加了不进行任何字符串转换的好处,因此它是纯算术处理(非常快),并且不依赖于任何日期格式。这充分利用了SQL Server datetime和smalldatetime值的内部表示为两个的事实。部分值,其第一部分是代表自1900年1月1日以来的天数的整数,第二部分是代表一天(该时间)的小数部分的十进制小数---所以整数值0(零)始终直接翻译为1900年1月1日午夜...

或者,由于@brinary的建议,

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

编辑于2014年10月。如@cade Roux所述,SQL 2012现在具有内置功能:
DATEFROMPARTS(year, month, day)
可以执行相同的操作。

编辑(2016年10月3日,(感谢@bambams注意到这一点,感谢@brinary修复它),最后一个解决方案,由@brinary提出。除非首先执行年份加法,否则似乎无法在leap年使用

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

36
@Brandon,您应该将此标记为此答案。这是最好的。作为其他StackOverflow阅读器的服务来进行。
Bill Paetzke 2010年

3
适用于leap年:选择dateadd(mm,(@ y-1900)* 12 + @m-1,0)+(@ d-1)
隐藏

8
传递无效的值组合(例如)时@Year = 2001,将导致有效但虚假的日期值,@Month = 13@DayOfMonth = 32导致2002-02-01T00:00:00.000。被Cade Roux接受的答案会产生一个错误,这会更有用。
2011年

6
您不必从零开始再加上天。您可以直接从@ DayOfMonth-1开始,然后添加月份和年份。那少了一个DateAdd()!
brianary 2011年

2
我的头还在旋转-真的没有更整齐的方法吗?(我的任务是修复SQL Server 2005中的查询)
PeterPerháč13年

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
MaciejJaśniaczyk

116

或仅使用单个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)

4
最佳答案IMO。具有查尔斯回答的所有优点,并且简短得多。
迈克尔

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

自2012年起开始在SQL和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 2012年

因为那行不通。您不能将0强制转换为datetime2。您的代码将返回“操作符类型冲突:int与datetime2不兼容”
Jack

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

如果您需要同时包含日期和时间部分的datetime 则添加一个单行解决方案:

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

3

尝试

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

2

对于低于12的SQL Server版本,我建议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


0

我个人更喜欢Substring,因为它提供了清理选项并能够根据需要拆分字符串。假设数据的格式为“ 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
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.