Crea una fecha del día mes y año con T-SQL

Estoy intentando convertir una fecha con partes individuales como 12, 1, 2007 en una fecha y hora en SQL Server 2005. He intentado lo siguiente:

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

pero esto da como resultado la fecha incorrecta. ¿Cuál es la forma correcta de convertir los tres valores de fecha en un formato de fecha y hora apropiado?

Suponiendo que y, m, d son todos int , ¿qué tal:

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

Por favor vea mi otra respuesta para SQL Server 2012 y superior

Prueba esto:

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

Funciona bien, tiene el beneficio añadido de no realizar conversiones de cadenas, por lo que es puro procesamiento aritmético (muy rápido) y no depende de ningún formato de fecha. Esto aprovecha el hecho de que la representación interna de SQL Server para los valores datetime y smalldatetime es un dos valor de parte cuya primera parte es un número entero que representa el número de días desde el 1 de enero de 1900, y la segunda parte es una fracción decimal que representa la porción fraccional de un día (por el tiempo) — Entonces el valor entero 0 (cero ) siempre se traduce directamente en la mañana de la medianoche del 1 de enero de 1900 …

o, gracias a la sugerencia de @brinary,

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

Editado en octubre de 2014. Según lo observado por @cade Roux, SQL 2012 ahora tiene una función incorporada:
DATEFROMPARTS(year, month, day)
eso hace lo mismo

Editado el 3 de octubre de 2016, (Gracias a @bambams por notar esto, y @brinary por solucionarlo), La última solución, propuesta por @brinary. no parece funcionar para años bisiestos a menos que se realice la adición de años primero

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

SQL Server 2012 tiene una nueva y esperada función DATEFROMPARTS (que generará un error si la fecha no es válida, mi principal objeción a una solución basada en DATEADD para este problema):

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

 DATEFROMPARTS(ycolumn, mcolumn, dcolumn) 

o

 DATEFROMPARTS(@y, @m, @d) 

O usando solo una función de fecha y hora simple:

 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 tiene una función que creará la fecha basada en las partes ( DATEFROMPARTS ). Para el rest de nosotros, he aquí una función db que he creado que determinará la fecha de las partes (gracias @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 

Puedes llamarlo así …

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

Devoluciones…

 2013-10-04 15:50:00.000 

Pruebe CONVERT en lugar de CAST.

CONVERT permite un tercer parámetro que indica el formato de fecha.

La lista de formatos está aquí: http://msdn.microsoft.com/en-us/library/ms187928.aspx

Actualizar después de que se haya seleccionado otra respuesta como la respuesta “correcta”:

Realmente no entiendo por qué se selecciona una respuesta que claramente depende de la configuración de NLS en su servidor, sin indicar esta restricción.

También puedes usar

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

Funciona en SQL desde la versión 2.012 y AzureSQL

Es más seguro y ordenado usar un punto de partida explícito ‘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 

Si no quiere mantener las cadenas fuera de esto, esto también funciona (Ponlo en una función):

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

Agrego una solución de una línea si necesita una fecha de partes de fecha y hora :

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

Tratar

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

Para las versiones de SQL Server inferiores a 12, puedo recomendar el uso de CAST en combinación con 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) 

cómo creas esas cuerdas depende de ti

Prueba esta consulta:

  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 

Resultado:

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

Personalmente prefiero la subcadena ya que proporciona opciones de limpieza y la capacidad de dividir la cadena según sea necesario. La suposición es que los datos tienen el formato ‘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) 

Aquí hay una demostración de cómo se puede demandar si los datos se almacenan en una columna. Huelga decir que es ideal para verificar el conjunto de resultados antes de aplicar a la columna

 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