Create a date from day month and year with T-SQL
我正在尝试将包含单个部分(如12、1、2007)的日期转换为SQL Server 2005中的日期时间。我尝试了以下方法:
1 | CAST(DATEPART(YEAR, DATE)+'-'+ DATEPART(MONTH, DATE) +'-'+ DATEPART(DAY, DATE) AS DATETIME) |
但这导致了错误的日期。将三个日期值转换为正确的日期时间格式的正确方法是什么?
试试这个:
2它也可以工作,不进行任何字符串转换的额外好处,所以它是纯算术处理(非常快),并且不依赖于任何日期格式。这是基于这样一个事实:SQL Server的datetime和smalldatetime值的内部表示是由两部分组成的值,第一部分是一个整数,表示自1900年1月1日以来的天数,第二部分是一个小数部分,表示一天的小数部分(对于时间而言)--因此整数值0(零)总是直接翻译成1900年1月1日午夜的早晨……
或者,多亏了@brinary的建议,
1 2 | SELECT DateAdd(yy, @Year-1900, DateAdd(m, @MONTH - 1, @DayOfMonth - 1)) |
编辑时间:2014年10月。正如@cade roux所指出的,SQL 2012现在具有内置功能:
编辑于2016年10月3日,(感谢@bambams注意到这一点,感谢@brinary修复),最后一个解决方案,由@brinary提出。除非先执行年份添加,否则在闰年似乎不起作用。
1 2 | SELECT dateadd(MONTH, @MONTH - 1, dateadd(YEAR, @Year-1900, @DayOfMonth - 1)); |
SQL Server 2012有一个出色的、期待已久的新datefromparts函数(如果日期无效,则会引发错误-我主要反对基于dateadd的此问题解决方案):
http://msdn.microsoft.com/en-us/library/hh213228.aspx
1 | DATEFROMPARTS(ycolumn, mcolumn, dcolumn) |
或
1 | DATEFROMPARTS(@y, @m, @d) |
假设
1 | CAST(CAST(y AS VARCHAR) + '-' + CAST(m AS VARCHAR) + '-' + CAST(d AS VARCHAR) AS DATETIME) |
请参阅我对SQL Server 2012及更高版本的其他答案
或者只使用一个dateadd函数:
1 2 3 4 | DECLARE @DAY INT, @MONTH INT, @YEAR INT SELECT @DAY = 4, @MONTH = 3, @YEAR = 2011 SELECT dateadd(mm, (@YEAR - 1900) * 12 + @MONTH - 1 , @DAY - 1) |
SQL Server 2012具有一个函数,该函数将根据部件(datefromparts)创建日期。对于我们中的其他人,这里有一个我创建的数据库函数,它将根据部件确定日期(谢谢@charles)…
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | 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 |
你可以这样称呼它…
1 | SELECT dbo.func_DateFromParts(2013, 10, 4, 15, 50, DEFAULT) |
回报…
1 | 2013-10-04 15:50:00.000 |
尝试转换而不是强制转换。
convert允许第三个参数指示日期格式。
格式列表如下:http://msdn.microsoft.com/en-us/library/ms187928.aspx
选择另一个答案作为"正确"答案后更新:
我真的不明白为什么选择的答案明显取决于服务器上的NLS设置,而没有指明这个限制。
您也可以使用
1 2 | SELECT DATEFROMPARTS(YEAR, MONTH, DAY) AS ColDate, Col2, Col3 FROM MyTable WHERE DATEFROMPARTS(YEAR, MONTH, DAY) BETWEEN @DateIni AND @DateEnd |
从2012年版开始在SQL和AzureSQL中工作
使用明确的起点"19000101"更安全、更整洁。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | 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 |
如果您同时需要日期和时间部分的日期时间,我会添加一个单行解决方案:
1 | SELECT dateadd(MONTH, (@YEAR -1900)*12 + @MONTH -1, @DayOfMonth -1) + dateadd(ss, @HOUR*3600 + @MINUTE*60 + @SECOND, 0) + dateadd(ms, @Millisecond, 0) |
如果您不想让字符串远离它,这也会起作用(将其放入函数中):
1 2 3 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'))) |
尝试
1 | CAST(STR(DATEPART(YEAR, DATE))+'-'+ STR(DATEPART(MONTH, DATE)) +'-'+ STR(DATEPART(DAY, DATE)) AS DATETIME) |
对于低于12的SQL Server版本,我建议结合使用
1 2 3 4 5 6 | -- 26 February 2015 SET DATEFORMAT dmy SELECT CAST('26-2-2015' AS DATE) SET DATEFORMAT ymd SELECT CAST('2015-2-26' AS DATE) |
如何创建这些字符串取决于您自己。
尝试这个查询:
1 2 3 | 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 |
结果:
1 2 3 4 5 6 7 | 2014 Ja 1 2015 Ja 1 2014 Ja 1 2015 Ja 1 2012 Ja 1 2010 Ja 1 2015 Ja 1 |
我个人更喜欢子字符串,因为它提供了清理选项和根据需要拆分字符串的能力。假设数据的格式为"dd,mm,yyyy"。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | --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) |
这里演示了如果数据存储在列中,如何起诉它。不用说,在应用到列之前检查结果集是理想的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | 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 |