web-dev-qa-db-de.com

Erstellen Sie ein Datum aus Tag, Monat und Jahr mit T-SQL

Ich versuche, ein Datum mit einzelnen Teilen wie 12, 1, 2007 in eine Datumszeit in SQL Server 2005 zu konvertieren. Ich habe Folgendes versucht:

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

dies führt jedoch zu einem falschen Datum. Was ist der richtige Weg, um aus den drei Datumswerten ein geeignetes Datums- und Uhrzeitformat zu machen?.

245
Brandon

Angenommen, y, m, d sind alle int, wie wäre es mit:

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

Siehe meine andere Antwort für SQL Server 2012 und höher

164
Cade Roux

Versuche dies:

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

Es funktioniert auch und hat den zusätzlichen Vorteil, dass keine Zeichenfolgenkonvertierungen durchgeführt werden. Daher ist es eine reine arithmetische Verarbeitung (sehr schnell) und es ist nicht von einem Datumsformat abhängig. Dies basiert auf der Tatsache, dass die interne Darstellung von SQL Server für datetime- und smalldatetime-Werte zwei ist Teilwert, dessen erster Teil eine Ganzzahl ist, die die Anzahl der Tage seit dem 1. Januar 1900 darstellt, und dessen zweiter Teil ein Dezimalbruch ist, der den Bruchteil eines Tages (für die Zeit) darstellt --- Also der Ganzzahlwert 0 (Null) ) übersetzt immer direkt in Mitternachtsmorgen vom 1. Januar 1900 ...

oder, dank des Vorschlags von @brinary,

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

Bearbeitet im Oktober 2014. Wie von @cade Roux bemerkt, verfügt SQL 2012 nun über eine integrierte Funktion:
DATEFROMPARTS(year, month, day)
das macht das selbe.

Bearbeitet am 3. Oktober 2016 (Dank an @bambams für das Bemerken und @brinary für das Reparieren), Die letzte von @brinary vorgeschlagene Lösung. scheint nicht für Schaltjahre zu funktionieren, es sei denn, die Addition von Jahren wird zuerst durchgeführt

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

SQL Server 2012 verfügt über eine wundervolle und lang erwartete neue DATEFROMPARTS-Funktion (die einen Fehler hervorruft, wenn das Datum ungültig ist - mein hauptsächlicher Einwand gegen eine DATEADD-basierte Lösung für dieses Problem):

http://msdn.Microsoft.com/de-de/library/hh213228.aspx

DATEFROMPARTS(ycolumn, mcolumn, dcolumn)

oder

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

Oder verwenden Sie nur eine einzige Dateadd-Funktion:

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 verfügt über eine Funktion, die das Datum basierend auf den Teilen erstellt ( DATEFROMPARTS ). Für den Rest von uns ist hier eine Db-Funktion, die ich erstellt habe, die das Datum aus den Teilen bestimmt (danke @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

Man kann es so nennen ...

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

Kehrt zurück...

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

Versuchen Sie CONVERT anstelle von CAST.

CONVERT erlaubt einen dritten Parameter, der das Datumsformat angibt.

Eine Liste der Formate finden Sie hier: http://msdn.Microsoft.com/de-de/library/ms187928.aspx

Aktualisieren, nachdem eine andere Antwort als "richtige" Antwort ausgewählt wurde:

Ich verstehe nicht wirklich, warum eine Antwort ausgewählt wird, die eindeutig von den NLS-Einstellungen auf Ihrem Server abhängt, ohne diese Einschränkung anzuzeigen.

12
devio

Sie können auch verwenden 

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

Funktioniert in SQL seit ver.2012 und Azure SQL

8
Marcelo Lujan

Es ist sicherer und übersichtlicher, einen expliziten Startpunkt '19000101' zu verwenden.

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

Ich füge eine einzeilige Lösung hinzu, wenn Sie eine datetime aus Datums- und Zeitangaben benötigen:

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

Wenn Sie Strings nicht heraushalten wollen, funktioniert das auch (Füge es in eine Funktion ein):

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

Versuchen 

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

Für SQL Server-Versionen unter 12 kann ich die Verwendung von CAST in Kombination mit SET DATEFORMAT empfehlen.

-- 26 February 2015
SET DATEFORMAT dmy
SELECT CAST('26-2-2015' AS DATE)

SET DATEFORMAT ymd
SELECT CAST('2015-2-26' AS DATE)

wie Sie diese Zeichenfolgen erstellen, liegt bei Ihnen

2
Konstantin

Versuchen Sie diese Abfrage:

    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

Ergebnis:

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

Ich weiß, dass das OP nach einer Antwort auf SQL 2005 fragt, aber die Frage ist ziemlich alt. Wenn Sie SQL 2012 oder höher ausführen, können Sie Folgendes verwenden:

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

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

1
Peter Bojanczyk

Ich persönlich bevorzuge Substrings, da es Bereinigungsoptionen bietet und die Möglichkeit besteht, die Zeichenfolge nach Bedarf zu teilen. Die Annahme ist, dass die Daten das Format 'TT, MM, JJJJ' haben.

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

Hier ist eine Demonstration, wie es verklagt werden kann, wenn die Daten in einer Spalte gespeichert sind. Es ist unnötig zu erwähnen, dass es ideal ist, die Ergebnismenge zu überprüfen, bevor Sie sie auf die Spalte anwenden

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