Buat tanggal dari hari bulan dan tahun dengan T-SQL

265

Saya mencoba untuk mengubah tanggal dengan bagian-bagian individual seperti 12, 1, 2007 menjadi datetime di SQL Server 2005. Saya telah mencoba yang berikut ini:

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

tetapi ini menghasilkan tanggal yang salah. Apa cara yang benar untuk mengubah nilai tanggal tiga menjadi format datetime yang tepat.

Brandon
sumber
8
Harap pertimbangkan untuk mengubah jawaban weblogs.sqlteam.com/jeffs/archive/2007/09/10/… yang
Brian Webster
DATEFROMPARTS (tahun, bulan, hari)
Kate

Jawaban:

175

Anggaplah y, m, dsemuanya int, bagaimana dengan:

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

Silakan lihat jawaban saya yang lain untuk SQL Server 2012 dan di atas

Cade Roux
sumber
Yang buruk. Buat saya dari ints tanggal 1 Januari 0001
Oleg Dok
24
Oleg SQL Server DateTime jangan melangkah lebih jauh saat itu 1753-01-01 sesuatu.
CodeMonkey
2
Jawaban ini tergantung pada pengaturan format tanggal, yang tergantung pada pengaturan regional server Anda jika Anda tidak menentukan. The yyyymmddFormat bekerja terlepas dari pengaturan tersebut. "String enam atau delapan digit selalu ditafsirkan sebagai ymd ." docs.microsoft.com/en-us/sql/t-sql/data-types/… Lihat jawaban ini: stackoverflow.com/a/46064419/2266979
Riley Major
339

Coba ini:

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

Ini berfungsi juga, telah menambahkan manfaat dari tidak melakukan konversi string, jadi ini adalah proses aritmatika murni (sangat cepat) dan tidak tergantung pada format tanggal apa pun. Ini memanfaatkan fakta bahwa representasi internal SQL Server untuk nilai datetime dan smalldatetime adalah dua. bagian nilai bagian pertama yang merupakan bilangan bulat yang mewakili jumlah hari sejak 1 Jan 1900, dan bagian kedua adalah pecahan desimal yang mewakili bagian fraksional satu hari (untuk saat itu) --- Jadi nilai bilangan bulat 0 (nol ) selalu diterjemahkan langsung ke Tengah malam pada tanggal 1 Jan 1900 ...

atau, terima kasih atas saran dari @brinary,

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

Diedit Oktober 2014. Seperti yang Dicatat oleh @cade Roux, SQL 2012 sekarang memiliki fungsi bawaan:
DATEFROMPARTS(year, month, day)
melakukan hal yang sama.

Diedit 3 Okt 2016, (Terima kasih kepada @bambams karena memperhatikan ini, dan @brinary untuk memperbaikinya), Solusi terakhir, diusulkan oleh @brinary. tampaknya tidak berfungsi selama tahun kabisat kecuali penambahan tahun dilakukan pertama kali

select dateadd(month, @Month - 1, 
     dateadd(year, @Year-1900, @DayOfMonth - 1)); 
Charles Bretana
sumber
36
@Brandon, Anda harus menandai ini sebagai jawaban ini sebagai gantinya. Itu yang terbaik. Lakukan itu sebagai layanan untuk pembaca StackOverflow lainnya.
Bill Paetzke
3
Bekerja untuk tahun kabisat: pilih dateadd (mm, (@ y-1900) * 12 + @m - 1,0) + (@ d-1)
disembunyikan
8
Menghasilkan nilai tanggal yang valid namun palsu ketika melewati kombinasi nilai yang tidak valid @Year = 2001, misalnya , @Month = 13dan @DayOfMonth = 32menghasilkan 2002-02-01T00:00:00.000. Jawaban yang diterima (oleh Cade Roux) menghasilkan kesalahan, yang lebih berguna.
onedaywhen
6
Anda tidak harus memulai dengan nol dan menambahkan hari. Anda dapat mulai langsung dengan @ DayOfMonth-1, lalu tambahkan bulan dan tahun. Itu kurang satu DateAdd ()!
brianary
2
kepalaku masih berputar - benar-benar tidak ada cara yang lebih rapi untuk melakukan ini? (Saya ditugaskan untuk memperbaiki kueri di SQL Server 2005)
Peter Perháči
241

SQL Server 2012 memiliki fungsi DATEFROMPARTS baru yang luar biasa dan telah lama ditunggu-tunggu (yang akan memunculkan kesalahan jika tanggal tidak valid - keberatan utama saya terhadap solusi berbasis DATEADD untuk masalah ini):

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

DATEFROMPARTS(ycolumn, mcolumn, dcolumn)

atau

DATEFROMPARTS(@y, @m, @d)
Cade Roux
sumber
11
Selanjutnya, merujuk pada pertanyaan asli, di mana objek Datetime disebutkan, ada juga fungsi yang disebut DATETIMEFROMPARTS: msdn.microsoft.com/pl-pl/library/hh213233%28v=sql.110%29.aspx
Maciej Jaśniaczyk
116

Atau hanya menggunakan fungsi dateadd tunggal:

DECLARE @day int, @month int, @year int
SELECT @day = 4, @month = 3, @year = 2011

SELECT dateadd(mm, (@year - 1900) * 12 + @month - 1 , @day - 1)
Shrike
sumber
4
jawaban terbaik IMO. Memiliki semua kelebihan jawaban Charles, dan jauh lebih pendek.
Michael
1
Sejauh ini yang paling bersih dan paling sederhana. Dan itu tidak melempar kesalahan ketika nilai hari di luar kisaran baik. Meskipun tergantung pada keadaan, kesalahan mungkin diinginkan, jadi hanya perlu diketahui bahwa ini membungkam nilai hari dan bulan yang berada di luar kisaran yang diharapkan.
Shawn Kovac
17

Sql Server 2012 memiliki fungsi yang akan membuat tanggal berdasarkan pada bagian-bagian ( DATEFROMPARTS ). Bagi kita semua, berikut adalah fungsi db yang saya buat yang akan menentukan tanggal dari bagian-bagian (terima kasih @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

Anda bisa menyebutnya seperti ini ...

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

Kembali ...

2013-10-04 15:50:00.000
Brian
sumber
12

Coba CONVERT, bukan CAST.

CONVERT memungkinkan parameter ketiga yang menunjukkan format tanggal.

Daftar format ada di sini: http://msdn.microsoft.com/en-us/library/ms187928.aspx

Perbarui setelah jawaban lain dipilih sebagai jawaban "benar":

Saya tidak benar-benar mengerti mengapa jawaban dipilih yang jelas tergantung pada pengaturan NLS di server Anda, tanpa menunjukkan batasan ini.

devio
sumber
Setuju formatnya harus memenuhi syarat, misalnya CONVERT (datetime2, CAST (@year AS varchar) + '.' + CAST (@month AS varchar) + '.' + CAST (@day AS varchar), 102)
Tony Wall
9

Anda juga bisa menggunakan

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

Bekerja di SQL sejak ver.2012 dan AzureSQL

Marcelo Lujan
sumber
6

Lebih aman dan lebih rapi untuk menggunakan titik awal eksplisit '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
Mendongkrak
sumber
Mengapa tidak menggunakan adil declare @output datetime2 = 0dan alih-alih @Year - 1900digunakan @Year - DATEPART(year,0);? Ini berfungsi tanpa gips dalam SQL Server 2008 dan jauh lebih jelas.
tsionyx
Karena itu tidak akan berhasil. Anda tidak dapat mengirimkan 0 ke datetime2. Kode Anda akan mengembalikan "Operan tipe clash: int tidak kompatibel dengan datetime2"
Jack
4

Jika Anda tidak ingin menghilangkan string, ini juga berfungsi (Masukkan fungsi):

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')))
Robert Wagner
sumber
4

Saya menambahkan solusi satu baris jika Anda memerlukan datetime dari bagian tanggal dan waktu :

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

Mencoba

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

Untuk versi SQL Server di bawah 12 saya dapat merekomendasikan penggunaan CASTdalam kombinasi denganSET DATEFORMAT

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

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

bagaimana Anda membuat string itu terserah Anda

Konstantin
sumber
1

Coba kueri ini:

    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

Hasil:

2014    Ja    1
2015    Ja    1
2014    Ja    1
2015    Ja    1
2012    Ja    1
2010    Ja    1
2015    Ja    1
pengguna3141962
sumber
0

Saya pribadi lebih suka Substring karena memberikan opsi pembersihan dan kemampuan untuk membagi string yang diperlukan. Asumsinya adalah bahwa data tersebut dalam format '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)

Berikut ini adalah demonstrasi bagaimana dapat digugat jika data disimpan dalam kolom. Tidak perlu dikatakan, ideal untuk memeriksa set-hasil sebelum menerapkan ke kolom

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
Gouri Shankar Aechoor
sumber