Utwórz datę z miesiąca miesiąca i roku za pomocą T-SQL


264

Próbuję przekonwertować datę z poszczególnymi częściami, takimi jak 12, 1, 2007, na datę i godzinę w SQL Server 2005. Próbowałem:

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

ale powoduje to niewłaściwą datę. Jaki jest prawidłowy sposób przekształcenia trzech wartości daty we właściwy format daty i godziny.


8
Proszę rozważyć zmianę zaakceptowanej odpowiedzi weblogs.sqlteam.com/jeffs/archive/2007/09/10/...
Brian Webster

DATAFROMPARTS (rok, miesiąc, dzień)
Kate

Odpowiedzi:


174

Zakładając, że y, m, dwszystkie int, a może:

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

Zobacz moją inną odpowiedź dla SQL Server 2012 i nowszych


Ten zły. Skomponuj mnie z daty 1 stycznia 0001
Oleg Dok

24
Oleg SQL Server DateTime nie iść dalej niż 1753-01-01 coś.
CodeMonkey

2
Ta odpowiedź zależy od ustawień formatu daty, które zależą od ustawień regionalnych twojego serwera, jeśli nie określisz. yyyymmddFormat działa niezależnie od tych ustawień. „Sześcio- lub ośmiocyfrowy ciąg jest zawsze interpretowany jako ymd ”. docs.microsoft.com/en-us/sql/t-sql/data-types/... Zobacz tę odpowiedź: stackoverflow.com/a/46064419/2266979
Riley Major

339

Spróbuj tego:

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

Działa również, ma dodatkową zaletę braku wykonywania konwersji ciągów, więc jest to czyste przetwarzanie arytmetyczne (bardzo szybkie) i nie jest zależne od żadnego formatu daty. Wykorzystuje to fakt, że wewnętrzna reprezentacja SQL Server dla wartości datetime i smalldatetime to dwa wartość części, której pierwsza część jest liczbą całkowitą reprezentującą liczbę dni od 1 stycznia 1900 r., a druga część jest ułamkiem dziesiętnym reprezentującym ułamkową część jednego dnia (dla czasu) --- Więc liczba całkowita 0 (zero ) zawsze przekłada się bezpośrednio na północ o północy 1 stycznia 1900 roku ...

lub, dzięki sugestii @brinary,

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

Edytowany w październiku 2014 r. Jak zauważył @cade Roux, SQL 2012 ma teraz wbudowaną funkcję:
DATEFROMPARTS(year, month, day)
robi to samo.

Edytowano 3 października 2016 r. (Podziękowania dla @bambams za zauważenie tego i @brinary za naprawienie tego), ostatnie rozwiązanie zaproponowane przez @brinary. nie wydaje się działać przez lata przestępne, chyba że dodawanie lat zostanie wykonane jako pierwsze

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

36
@Brandon, powinieneś zaznaczyć to jako odpowiedź. To jest najlepsze. Zrób to jako usługa dla innych czytników StackOverflow.
Bill Paetzke,

3
Działa na lata przestępne: wybierz dateadd (mm, (@ y-1900) * 12 + @m - 1,0) + (@ d-1)
ukryty

8
Wyniki w ważnej jeszcze pozornej wartości daty, kiedy przeszedł nieprawidłową kombinację wartości np @Year = 2001, @Month = 13a @DayOfMonth = 32wyniki w 2002-02-01T00:00:00.000. Zaakceptowana odpowiedź (autor: Cade Roux) generuje błąd, który jest bardziej przydatny.
poniedziałek

6
Nie musisz zaczynać od zera i dodawać dni. Możesz zacząć bezpośrednio od @ DayOfMonth-1, a następnie dodać miesiące i lata. To o jeden mniej DateAdd ()!
Brianary

2
moja głowa wciąż się kręci - naprawdę nie ma lepszego sposobu na zrobienie tego? (Mam zadanie naprawić zapytanie w SQL Server 2005)
Peter Perháč

241

SQL Server 2012 ma wspaniałą i długo oczekiwaną nową funkcję DATEFROMPARTS (która wywoła błąd, jeśli data jest nieprawidłowa - mój główny sprzeciw wobec rozwiązania tego problemu opartego na DATEADD):

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

DATEFROMPARTS(ycolumn, mcolumn, dcolumn)

lub

DATEFROMPARTS(@y, @m, @d)

11
Ponadto, odnosząc się do pierwotnego pytania, w którym wspomniano o obiekcie Datetime, istnieje również funkcja o nazwie DATETIMEFROMPARTS: msdn.microsoft.com/pl-pl/library/hh213233%28v=sql.110%29.aspx
Maciej Jaśniaczyk

116

Lub używając tylko jednej funkcji 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
najlepsza odpowiedź IMO. Ma wszystkie zalety odpowiedzi Charlesa i jest znacznie krótszy.
Michael

1
Jest to zdecydowanie najczystsze i najprostsze. Nie generuje też błędu, gdy wartości dzienne są poza zakresem. Mimo to w zależności od okoliczności może być pożądany błąd, więc należy pamiętać, że wycisza to wartości dzienne i miesięczne, które są poza oczekiwanym zakresem.
Shawn Kovac

16

Sql Server 2012 ma funkcję, która utworzy datę na podstawie części ( DATEFROMPARTS ). Dla reszty z nas utworzyłem funkcję db, która określi datę na podstawie części (dzięki @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

Możesz to tak nazwać ...

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

Zwroty...

2013-10-04 15:50:00.000

12

Spróbuj CONVERT zamiast CAST.

CONVERT pozwala na trzeci parametr wskazujący format daty.

Lista formatów znajduje się tutaj: http://msdn.microsoft.com/en-us/library/ms187928.aspx

Zaktualizuj po wybraniu innej odpowiedzi jako „poprawnej”:

Naprawdę nie rozumiem, dlaczego wybrano odpowiedź, która wyraźnie zależy od ustawień NLS na twoim serwerze, bez wskazania tego ograniczenia.


Zgadzam się, że format musi zostać zakwalifikowany, np. CONVERT (datetime2, CAST (@year AS varchar) + '.' + CAST (@month AS varchar) + '.' + CAST (@day AS varchar), 102)
Tony Wall

9

Możesz także użyć

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

Działa w SQL od wersji 2012 i AzureSQL


6

Bezpieczniej i schludniej jest stosować wyraźny punkt początkowy „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

Dlaczego nie używać tylko declare @output datetime2 = 0i zamiast @Year - 1900używać @Year - DATEPART(year,0);? Działa to bez żadnych rzutowań w SQL Server 2008 i znacznie bardziej przejrzyste.
tsionyx

Ponieważ to nie zadziała. Nie możesz rzutować 0 na datetime2. Twój kod zwróci „Zderzenie typu argumentu: int jest niezgodne z datetime2”
Jack

4

Jeśli nie chcesz, aby łańcuchy były poza tym, działa to również (Umieść w funkcji):

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

Dodaję rozwiązanie jednowierszowe, jeśli potrzebujesz daty i godziny z części daty i godziny :

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

3

Próbować

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

2

W przypadku wersji SQL Server poniżej 12 mogę zalecić użycie CASTw połączeniu zSET DATEFORMAT

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

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

jak utworzysz te ciągi, zależy od ciebie


1

Spróbuj tego zapytania:

    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

Wynik:

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


0

Ja osobiście wolę Substring, ponieważ zapewnia opcje czyszczenia i możliwość podziału łańcucha w razie potrzeby. Zakłada się, że dane mają format „dd, mm, rrrr”.

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

Oto demonstracja, w jaki sposób można go pozwać, jeśli dane są przechowywane w kolumnie. Nie trzeba dodawać, że idealnie sprawdza się zestaw wyników przed zastosowaniem do kolumny

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
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.