2008-11-05 8 views
232

Je suis en train de convertir une date avec des pièces individuelles telles que 12, 1, 2007 dans un datetime dans SQL Server 2005. Je l'ai essayé ce qui suit:Créer une date avec T-SQL

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

mais résultats à la mauvaise date. Quelle est la bonne façon de transformer les trois valeurs de date en un format datetime approprié.

+6

S'il vous plaît envisager de changer votre réponse acceptée http://weblogs.sqlteam.com/jeffs/archive/2007/09/10/group-by-month-sql.aspx –

Répondre

159

En supposant y, m, d sont tous int, que diriez-vous:

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

S'il vous plaît voir my other answer pour SQL Server 2012 et au-dessus

+0

Mauvais. Composez-moi à partir de la date du 1er Janvier 0001 –

+22

Oleg SQL Server DateTime ne pas aller plus loin, puis 1753-01-01 quelque chose. – CodeMonkey

+0

Cette réponse dépend des paramètres de format de date, qui dépendent des paramètres régionaux de votre serveur si vous ne spécifiez pas. Le format 'yyyymmdd' fonctionne indépendamment de ces paramètres. "Une chaîne de six ou huit chiffres est toujours interprétée comme * ymd *." https://docs.microsoft.com/en-us/sql/t-sql/data-types/date-transact-sql#ansi-and-iso-8601-compliance Voir cette réponse: https://stackoverflow.com/a/46064419/2266979 –

12

Essayez CONVERT au lieu de CAST.

CONVERT permet un troisième paramètre indiquant le format de la date.

Liste des formats est ici: http://msdn.microsoft.com/en-us/library/ms187928.aspx

Mise à jour après une autre réponse a été choisie comme la « bonne » réponse:

Je ne comprends pas vraiment pourquoi une réponse est sélectionnée qui dépend clairement du SNA paramètres sur votre serveur, sans indiquer cette restriction.

+0

Accepter que le format doive être qualifié, par ex. CONVERT (datetime2, CAST (@year AS varchar) + '.' + CAST (@month AS varchar) + '.' + CAST (@jour AS varchar), 102) –

4

Si vous ne souhaitez pas conserver les chaînes hors de lui, cela fonctionne aussi bien (Mettez en fonction):

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

Essayez ceci:

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

Il fonctionne aussi bien, a ajouté avantage de ne pas faire des conversions de chaînes, il est donc le traitement arithmétique pur (très rapide) et il ne dépend d'aucun format de date Cette capitalise sur le fait que la représentation interne de SQL Server pour datetime et smalldatetime values ​​est une valeur en deux parties dont la première partie est un entier représentant le nombre de jours depuis le 1er janvier 1900, et la seconde partie est une fraction décimale représentant la partie fractionnaire d'un jour (pour le temps) --- So la valeur entière 0 (zéro) se traduit toujours directement minuit matin du 1 janvier 1900 ...

ou, grâce à la suggestion de @brinary,

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

Modifié Octobre 2014. Comme il est indiqué par @cade Roux, SQL 2012 dispose désormais d'une fonction intégrée:
DATEFROMPARTS(year, month, day)
qui fait la même chose.

Édité 3 Oct 2016, (Merci à @bambams pour avoir remarqué cela, et @brinary pour le corriger), La dernière solution, proposée par @brinary.ne semble pas travailler pendant des années bissextiles à moins années addition est effectuée en premier

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

@Brandon, vous devriez marquer ceci comme cette réponse à la place. C'est le meilleur. Faites-le comme un service à d'autres lecteurs StackOverflow. –

+3

Fonctionne pour les années bissextiles: sélectionnez dateadd (mm, (@ y-1900) * 12 + @m - 1,0) + (@ d-1) – hidden

+8

Affiche une valeur de date valide mais non valide lors de la transmission d'une combinaison de valeurs non valide, par ex. '@Year = 2001',' @Month = 13' et '@DayOfMonth = 32' donne' 2002-02-01T00: 00: 00.000'. La réponse acceptée (par Cade Roux) génère une erreur, ce qui est plus utile. – onedaywhen

115

Ou en utilisant une seule fonction 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

meilleure réponse IMO. A tous les avantages de la réponse de Charles, et est beaucoup plus courte. – Michael

+1

C'est de loin le plus propre et le plus simple. Et il ne génère pas d'erreur lorsque les valeurs du jour sont hors de portée non plus. Bien que cela dépende de la situation, une erreur peut être désirée, alors sachez que cela réduit au silence les valeurs du jour et du mois qui sont hors de la fourchette attendue. –

210

SQL Server 2012 a un merveilleux et très attendue nouvelle fonction DATEFROMPARTS (ce qui déclenche une erreur si la date est invalide - ma principale objection à une solution basée DATEADD à ce problème):

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

DATEFROMPARTS(ycolumn, mcolumn, dcolumn) 

ou

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

Par ailleurs, en référence à la question d'origine, où l'objet Datetime a été mentionné, il existe également une fonction appelée DATETIMEFROMPARTS: https://msdn.microsoft.com/pl-pl/library/hh213233%28v=sql.110%29.aspx –

6

Il est plus sûr et plus propre d'utiliser un point de départ explicite '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

Pourquoi ne pas utiliser simplement 'declare @output datetime2 = 0' et au lieu de' @Year - 1900' utiliser '@Year - DATEPART (année, 0);'? Cela fonctionne sans moulage dans SQL Server 2008 et beaucoup plus clair. – tsionyx

+0

Parce que cela ne fonctionnera pas. Vous ne pouvez pas diffuser 0 en datetime2. Votre code renverra "Conflit de type d'opérande: int est incompatible avec datetime2" – Jack

3

Essayez

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

Sql Server 2012 a une fonction qui permettra de créer la date basée sur les pièces (DATEFROMPARTS). Pour le reste d'entre nous, voici une fonction db j'ai créé qui déterminera la date des parties (grâce @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 

Vous pouvez l'appeler comme ça ...

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

... Retours

2013-10-04 15:50:00.000 
4

ajouter une solution d'une ligne si vous avez besoin d'un datetime des deux parties de la date et l'heure:

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

Pour les versions SQL Server ci-dessous 12 je peux recommander l'utilisation de CAST en combinaison avec 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) 

comment créer ces chaînes est à vous

1

Essayez cette requête:

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 

Résultat:

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

Personnellement, je préfère Substring car il fournit des options de nettoyage et la capacité de diviser la chaîne au besoin. L'hypothèse est que les données sont au format 'jj, mm, aaaa'.

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

Voici une démonstration de la façon dont il peut être poursuivi si les données sont stockées dans une colonne.Inutile de dire que son idéal pour vérifier le jeu de résultats avant d'appliquer à la colonne

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

Vous pouvez également utiliser

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

Works dans SQL depuis ver.2012 et AzureSQL

Questions connexes