T-SQL ile gün ay ve yıldan tarih oluşturma


264

SQL Server 2005'te bir tarih 12, 1, 2007 gibi tek tek parçalarla bir tarih dönüştürmek çalışıyorum. Aşağıdaki denedim:

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

ancak bu yanlış tarihle sonuçlanır. Üç tarih değerini uygun bir tarih / saat biçimine dönüştürmenin doğru yolu nedir?


8
Lütfen kabul ettiğiniz yanıtı değiştirmeyi düşünün weblogs.sqlteam.com/jeffs/archive/2007/09/10/…
Brian Webster

DATEFROMPARTS (yıl, ay, gün)
Kate

Yanıtlar:


174

y, m, dHepsi varsayalım int, nasıl olur:

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

Lütfen SQL Server 2012 ve sonraki sürümler için diğer yanıtımı inceleyin


Kötü olan. Beni 1 Ocak 0001
Oleg Dok

24
Oleg SQL Server DateTime 1753-01-01 sonra bir şey daha ileri gitmeyin.
CodeMonkey

2
Bu yanıt, belirtmezseniz sunucunuzun bölgesel ayarlarına bağlı olan tarih biçimi ayarlarına bağlıdır. yyyymmddBiçimi ne olursa olsun, bu ayarlardan çalışır. "Altı veya sekiz basamaklı bir dize her zaman ymd olarak yorumlanır ." docs.microsoft.com/tr-tr/sql/t-sql/data-types/… Bu cevaba bakınız: stackoverflow.com/a/46064419/2266979
Riley Major

339

Bunu dene:

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

Aynı zamanda çalışır, herhangi bir dize dönüştürme yapmamanın faydasını ekledi, bu yüzden saf aritmetik işleme (çok hızlı) ve herhangi bir tarih biçimine bağlı değil. Bu, SQL Server'ın datetime ve smalldatetime değerleri için iç temsilinin iki birinci kısmı 1 Ocak 1900'den bu yana geçen gün sayısını temsil eden bir tam sayıdır ve ikinci kısım bir günün (zaman için) kesirli kısmını temsil eden ondalık bir kesirdir --- Yani tamsayı değeri 0 (sıfır ) her zaman doğrudan 1 Ocak 1900'ün gece yarısı sabahına çevirir ...

veya @brinary'nin önerisi sayesinde,

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

Ekim 2014'te düzenlendi. @Cade Roux tarafından not edildiği gibi, SQL 2012'nin artık yerleşik bir işlevi var:
DATEFROMPARTS(year, month, day)
bu da aynı şeyi yapıyor.

Düzenlendi 3 Eki 2016, (@bambams bunu fark ettiğiniz için ve @brinary düzeltmek için teşekkürler), @brinary tarafından önerilen son çözüm. önce yıl ilavesi yapılmadığı sürece artık yıllar boyunca çalışmıyor gibi görünüyor

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

36
@Brandon, bunun yerine bu cevap olarak işaretlemelisin. En iyisi bu. Bunu diğer StackOverflow okuyuculara bir hizmet olarak yapın.
Bill Paetzke

3
Artık yıllar için çalışıyor: dateadd (mm, (@ y-1900) * 12 + m - 1,0) + (@ d-1)
gizli

8
Örneğin @Year = 2001, geçersiz değer birleşimi iletildiğinde geçerli ancak sahte bir tarih değeriyle sonuçlanır @Month = 13ve @DayOfMonth = 32sonuçlanır 2002-02-01T00:00:00.000. Kabul edilen cevap (Cade Roux tarafından) daha faydalı bir hata üretir.
oneday14

6
Sıfır ile başlamak ve gün eklemek zorunda değilsiniz. Doğrudan @ DayOfMonth-1 ile başlayabilir, ardından ayları ve yılları ekleyebilirsiniz. Bu bir tane daha DateAdd ()!
brianary

2
kafam hala dönüyor - bunu yapmanın daha temiz bir yolu yok mu? (SQL Server 2005'te bir sorguyu düzeltmekle görevlendirildim)
Peter Perháč 20:13


116

Veya sadece tek bir dateadd işlevi kullanarak:

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
en iyi cevap IMO. Charles'ın cevabının tüm avantajlarına sahiptir ve çok daha kısadır.
Michael

1
Bu açık ara en temiz ve en basit olanıdır. Ve gün değerleri aralık dışında olduğunda da hata vermez. Duruma bağlı olarak bir hata istenebilir, bu yüzden bu değerin beklenen aralık dışındaki gün ve ay değerlerini susturduğunu unutmayın.
Shawn Kovac

16

Sql Server 2012, parçalara ( DATEFROMPARTS ) dayalı tarih yaratacak bir işleve sahiptir . Geri kalanımız için, parçalardan tarihi belirleyeceğim bir db işlevi var (teşekkürler @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

Buna şöyle diyebilirsiniz ...

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

İadeler...

2013-10-04 15:50:00.000

12

CAST yerine CONVERT seçeneğini deneyin.

CONVERT, tarih biçimini gösteren üçüncü bir parametreye izin verir.

Biçimlerin listesi burada: http://msdn.microsoft.com/en-us/library/ms187928.aspx

"Doğru" cevap olarak başka bir cevap seçildikten sonra güncelleme:

Bu kısıtlamayı belirtmeden, sunucunuzdaki NLS ayarlarına açıkça bağlı olan bir yanıtın neden seçildiğini gerçekten anlamıyorum.


Biçimin nitelikli olması gerektiğini kabul edin, örn. CONVERT (datetime2, CAST (@year AS varchar) + '.' + CAST (@month AS varchar) + '.' + CAST (@day AS varchar), 102)
Tony Wall

9

Ayrıca kullanabilirsiniz

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

Ver.2012 ve AzureSQL'den beri SQL'de çalışır


6

Açık bir başlangıç ​​noktası '19000101' kullanmak daha güvenli ve daha düzenli

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

Neden sadece declare @output datetime2 = 0ve @Year - 1900kullanmak yerine kullanmıyorsunuz @Year - DATEPART(year,0);? Bu, SQL Server 2008'de herhangi bir döküm olmadan çalışır ve çok daha net.
tsionyx

Çünkü bu işe yaramaz. 0'ı datetime2 öğesine atayamazsınız. Kodunuz "İşlenen türü çakışması: int datetime2 ile uyumsuz" döndürür
Jack

4

Dizeleri dışarıda tutmak istemiyorsanız, bu da işe yarar (Bir işleve koyun):

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

Hem tarih hem de saat bölümlerinden bir tarih saatine ihtiyacınız varsa tek satırlık bir çözüm ekliyorum :

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

3

Deneyin

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

2

12 yaşından küçük SQL Server sürümleri CASTiçinSET DATEFORMAT

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

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

bu dizeleri nasıl yarattığın size kalmış


1

Bu sorguyu deneyin:

    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

Sonuç:

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


0

Kişisel olarak temizlik seçenekleri ve dizeyi gerektiği gibi bölme yeteneği sağladığı için Substring'i tercih ederim. Varsayım, verilerin 'gg, aa, yyyy' biçiminde olmasıdır.

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

Verilerin bir sütunda depolanması durumunda nasıl dava edilebileceğinin bir göstergesidir. Söylemeye gerek yok, sütuna uygulamadan önce sonuç kümesini kontrol etmek ideal

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
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.