web-dev-qa-db-fra.com

Créez une date à partir du mois, du mois et de l'année avec T-SQL

J'essaie de convertir une date avec des pièces individuelles telles que 12, 1, 2007 en une date/heure dans SQL Server 2005. J'ai essayé les solutions suivantes:

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

mais cela donne une mauvaise date. Quelle est la bonne façon de convertir les trois valeurs de date en un format de date/heure approprié?.

245
Brandon

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

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

Veuillez consulter mon autre réponse pour SQL Server 2012 et versions ultérieures

164
Cade Roux

Essaye ça:

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

Cela fonctionne aussi, offre l’avantage supplémentaire de ne pas effectuer de conversions de chaînes. Il s’agit donc d’un traitement arithmétique pur (très rapide) et ne dépend pas du format de date. Il tire parti du fait que la représentation interne de SQL Server pour les valeurs datetime et smalldatetime est deux la valeur de la partie 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 décimale d'un jour (pour l'heure) --- Donc la valeur entière 0 (zéro) ) traduit toujours directement à minuit le matin du 1er janvier 1900 ...

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

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

Édité en octobre 2014. Comme noté par @cade Roux, SQL 2012 a maintenant une fonction intégrée:
DATEFROMPARTS(year, month, day)
Cela fait la même chose.

Édité le 3 oct. 2016, (Merci à @bambams pour l'avoir remarqué et à @brinary pour l'avoir corrigé), dernière solution proposée par @brinary. ne semble pas fonctionner pendant des années bissextiles à moins que les années ne soient ajoutées en premier

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

SQL Server 2012 a une nouvelle fonction DATEFROMPARTS merveilleuse et attendue (qui générera une erreur si la date est invalide - ma principale objection à une solution à ce problème basée sur DATEADD):

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

DATEFROMPARTS(ycolumn, mcolumn, dcolumn)

ou

DATEFROMPARTS(@y, @m, @d)
224
Cade Roux

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

SQL Server 2012 a une fonction qui créera la date en fonction des pièces ( DATEFROMPARTS ). Pour le reste d’entre nous, voici une fonction de base de données que j’ai créée et qui déterminera la date des parties (merci @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)

Résultats...

2013-10-04 15:50:00.000
16
Brian

Essayez CONVERT au lieu de CAST.

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

La liste des formats est ici: http://msdn.Microsoft.com/en-us/library/ms187928.aspx

Mettre à jour après qu'une autre réponse a été sélectionnée comme réponse "correcte":

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

12
devio

Vous pouvez aussi utiliser 

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

Fonctionne en SQL depuis ver.2012 et Azure SQL

8
Marcelo Lujan

Il est plus sûr et plus judicieux 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
6
Jack

J'ajoute une solution sur une ligne si vous avez besoin d'une date/heure à partir de parties de date et d'heure:

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

Si vous ne voulez pas garder les chaînes hors de celui-ci, cela fonctionne aussi (mettez-le dans une 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')))
4
Robert Wagner

Essayer 

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

Pour les versions de SQL Server inférieures à 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 vous créez ces chaînes dépend de vous

2
Konstantin

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
1
user3141962

Je sais que l'OP demande une réponse à SQL 2005, mais la question est assez ancienne. Par conséquent, si vous utilisez SQL 2012 ou une version ultérieure, vous pouvez utiliser les éléments suivants:

SELECT DATEADD(DAY, 1, EOMONTH(@somedate, -1))

Référence: https://docs.Microsoft.com/en-us/sql/t-sql/functions/eomonth-transact-sql?view=sql-server-2017&viewFallbackFrom=sql-server-previousversions

1
Peter Bojanczyk

Personnellement, je préfère Substring car il fournit des options de nettoyage et la possibilité de scinder la chaîne si nécessaire. 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 résultat 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
0