2008-11-05 11 views
232

Estoy tratando de convertir una fecha con partes individuales, tales como 12, 1, 2007 en una fecha y hora en SQL Server 2005. He intentado lo siguiente:Crear una cita con T-SQL

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?

+6

favor considere cambiar su respuesta aceptada http://weblogs.sqlteam.com/jeffs/archive/2007/09/10/group-by-month-sql.aspx –

Respuesta

159

Suponiendo 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 my other answer para SQL Server 2012 y por encima de

+0

Malo. Coméntame desde la fecha del 1 de enero de 0001 –

+22

Oleg SQL Server DateTime no ir más allá en 1753-01-01 algo. – CodeMonkey

+0

Esta respuesta depende de la configuración del formato de fecha, que depende de la configuración regional de su servidor si no especifica. El formato 'aaaammdd' funciona independientemente de esas configuraciones. "Una cadena de seis u ocho dígitos siempre se interpreta como * ymd *." https://docs.microsoft.com/en-us/sql/t-sql/data-types/date-transact-sql#ansi-and-iso-8601-compliance Ver esta respuesta: https://stackoverflow.com/a/46064419/2266979 –

12

Pruebe CONVERT en lugar de CAST.

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

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

Update después de otra respuesta ha sido seleccionada como la "correcta" la respuesta:

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

+0

De acuerdo en que el formato necesita ser calificado, por ej. CONVERTIR (datetime2, CAST (@year AS varchar) + '.' + CAST (@month AS varchar) + '.' + CAST (@day AS varchar), 102) –

4

Si no desea mantener las cadenas de ella, esto funciona así (Póngalo 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'))) 
317

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 tan bien, ha añadido el beneficio de no hacer ninguna conversión de series, por lo que es un proceso aritmético puro (muy rápido) y no es dependiente de ningún formato de fecha Este capitaliza en el hecho de que la representación interna de SQL Server para la fecha y hora y smalldatetime values ​​es un valor de dos partes cuya primera parte es un 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 parte fraccional de un día (por el tiempo) --- Entonces el valor entero 0 (cero) siempre se traduce directamente en la medianoche mañana del 1 Ene 1900 ...

o, gracias a la sugerencia de @brinary,

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

Editado octubre de 2014. Como se ha señalado por @cade Roux, SQL 2012 ahora tiene una función incorporada:
DATEFROMPARTS(year, month, day)
que hace lo mismo.

Editado 3 de octubre de 2016, (Gracias a @bambams por notar esto, y @brinary por arreglarlo), La última solución, propuesta por @brinary.no parece funcionar para años bisiestos menos años además se realiza primero

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

@Brandon, debe marcar esto como esta respuesta en su lugar. Es el mejor. Hágalo como un servicio a otros lectores de StackOverflow. –

+3

Funciona para años bisiestos: seleccione fechaadd (mm, (@ y-1900) * 12 + @m - 1,0) + (@ d-1) – hidden

+8

Resultados en un valor de fecha válido pero espurio cuando se pasa una combinación inválida de valores, p. '@Year = 2001',' @Month = 13' y '@DayOfMonth = 32' da como resultado' 2002-02-01T00: 00: 00.000'. La respuesta aceptada (por Cade Roux) genera un error, que es más útil. – onedaywhen

115

O usando sólo una única función 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

mejor respuesta IMO. Tiene todas las ventajas de la respuesta de Charles, y es mucho más corto. – Michael

+1

Este es de lejos el más limpio y simple. Y tampoco arroja un error cuando los valores del día están fuera de rango. Aunque dependiendo de la circunstancia, un error puede ser deseado, así que tenga en cuenta que esto silencia los valores de día y mes que están fuera del rango esperado. –

210

SQL Server 2012 tiene una nueva función maravilloso y tan esperado DATEFROMPARTS (lo que elevará un error si la fecha no es válida - mi principal objeción a una solución basada en DATEADD a este problema):

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

DATEFROMPARTS(ycolumn, mcolumn, dcolumn) 

o

DATEFROMPARTS(@y, @m, @d) 
+7

Además, refiriéndose a la pregunta original, donde se mencionó el objeto Datetime, también hay una función llamada DATETIMEFROMPARTS: https://msdn.microsoft.com/pl-pl/library/hh213233%28v=sql.110%29.aspx –

6

Es más seguro y más limpio de utilizar un punto de partida explícita '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 
+0

¿Por qué no usar simplemente 'declare @output datetime2 = 0' y en lugar de' @Year - 1900' usar '@Year - DATEPART (año, 0);'? Esto funciona sin ningún molde en SQL Server 2008 y es mucho más claro. – tsionyx

+0

Porque eso no funcionará. No puedes convertir 0 a datetime2. Su código devolverá "Operand type clash: int es incompatible con datetime2" – Jack

3

Trate

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

SQL Server 2012 tiene una función que va a crear la fecha se basa en las partes (DATEFROMPARTS). Para el resto de nosotros, aquí es una función db creé que determinará la fecha a partir 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 

Se le puede llamar así ...

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

devoluciones ...

2013-10-04 15:50:00.000 
4

añado una solución de una línea si necesita una fecha y hora de ambas 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) 
2

Para las versiones de SQL Server por debajo de 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) 

la forma de crear esas cadenas depende de usted

1

Intentar 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 
0

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.Ni que decir tiene, que es ideal para comprobar 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 
8

También puede utilizar

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

Obras en SQL desde ver.2012 y AzureSQL

Cuestiones relacionadas