SQL Server'da bir tarih saatini nasıl kısaltabilirim?


281

SQL Server 2008'de datetime değerini (saat dakika ve saniye kaldırmak için) kısaltmanın en iyi yolu nedir?

Örneğin:

declare @SomeDate datetime = '2009-05-28 16:30:22'
select trunc_date(@SomeDate)

-----------------------
2009-05-28 00:00:00.000

Yanıtlar:


495

Bu, birkaç yıl sonra bile sık sık ek oy toplamaya devam ediyor ve bu yüzden Sql Server'ın modern sürümleri için güncellemem gerekiyor. Sql Server 2008 ve üzeri için basit:

cast(getDate() As Date)

En alttaki son üç paragrafın hala geçerli olduğunu ve genellikle bir adım geriye gitmeniz ve ilk etapta dökümden kaçınmanın bir yolunu bulmanız gerektiğini unutmayın.

Ancak bunu başarmanın başka yolları da var. İşte en yaygın olanları.

Doğru yol (Sql Server 2008'den beri yeni):

cast(getdate() As Date)

Doğru yol (eski):

dateadd(dd, datediff(dd,0, getDate()), 0)

Bu şimdi daha eski, ama yine de bilmeye değer çünkü ayın ilk dakikası, dakikası, saati veya yılı gibi diğer zaman noktalarına da kolayca uyum sağlayabilir.

Bu doğru yol, ansi standardının bir parçası olan ve çalışması garanti edilen belgelenmiş işlevleri kullanır, ancak biraz daha yavaş olabilir. 0. günden geçerli güne kaç gün olduğunu bularak ve bunu o güne 0 gününe ekleyerek çalışır. Tarih saatiniz ne kadar saklanırsa saklansanız da yerel ayarınız ne olursa olsun çalışır.

Hızlı yolu:

cast(floor(cast(getdate() as float)) as datetime)

Bu, datetime sütunlarının 8 baytlık ikili değerler olarak depolanması nedeniyle çalışır. Onları kayan noktaya yayınlayın, kesriyi kaldırmak için katlayın ve değerlerin tarih bölümüne geri döndüğünüzde değerlerin zaman kısmı kaybolur. Her şey karmaşık bir mantık olmadan biraz değişiyor ve çok hızlı.

Bunun, bir otomatik hizmet güncellemesinde bile Microsoft'un istediği zaman değiştirmekte özgür olduğu bir uygulama ayrıntısına bağlı olduğunu unutmayın. Ayrıca çok taşınabilir değil. Uygulamada, bu uygulamanın yakında herhangi bir zamanda değişmesi pek olası değildir, ancak kullanmayı seçerseniz tehlikenin farkında olmak hala önemlidir. Ve şimdi tarih olarak yayınlama seçeneğimiz olduğuna göre, nadiren gerekli.

Yanlış yol:

cast(convert(char(11), getdate(), 113) as datetime)

Yanlış yol, bir dizeye dönüştürerek, dizeyi keserek ve bir datetime dönüştürerek çalışır. Bu var yanlış iki nedenden dolayı,: 1) bu olabilir değil tüm yerel genelinde çalışma ve 2) sadece biraz değil bunu yapmak mümkün olan en yavaş yol hakkında ... ve; diğer seçeneklerden daha büyük veya iki daha yavaş bir sıra gibidir.


Güncelleme Bu son zamanlarda bazı oylar alıyor ve bu yüzden bunu yayınladığımdan beri Sql Server'ın "doğru" yol ile "hızlı" yol arasındaki performans farkını optimize edeceğine dair oldukça sağlam kanıtlar gördüğümü eklemek istiyorum. yani şimdi birincisini tercih etmelisiniz.

Her iki durumda da, ilk etapta bunu yapmaktan kaçınmak için sorgularınızı yazmak istersiniz . Bu işi veritabanında yapmanız çok nadirdir.

Çoğu yerde, veritabanı zaten darboğazınızdır. Genellikle performans iyileştirmeleri için donanım eklemek için en pahalı ve bu eklemeleri doğru yapmak için en zor olan sunucudur (örneğin, diskleri bellekle dengelemek zorundasınız). Hem teknik olarak hem de iş açısından dışa doğru ölçeklendirmek de en zor olanı; teknik olarak web veya uygulama sunucusu eklemek bir veritabanı sunucusundan çok daha kolaydır ve bu yanlış olsa bile IIS veya apache için sunucu lisansı başına 20.000 $ + ödemezsiniz.

Yapmaya çalıştığım nokta, mümkün olduğunda bu işi uygulama düzeyinde yapmanız gerektiğidir. Sadece gündüzleri gruba gerekir ve buna genelde ekleme / güncelleme sırasında tutulan bir bilgisayarlı sütun olarak ayarlanmış fazladan bir sütun, olması gereken ya da bakımı yapıldığında Hiç kendinizi Sql Server üzerinde bir datetime kesiliyor bulmalısınız zamanı uygulama mantığında. Bu dizin kırıcı, cpu-ağır iş veritabanından alın.


6
"hızlı yol" hala koştum bir kıyaslamaya göre sql 2008 için en hızlı yoludur
Sam Saffron

3
Bilginize: stackoverflow.com/q/1177449/27535 ve stackoverflow.com/q/133081/27535 Dateadd / tarihli "kazanır ...". Elbette kimin umurunda olduğu tek bir değişken ve sütunları veya bir milyondan fazla satırı hesaplamanızı umuyor :-)
gbn

9
Bu "doğru" yol sadece yanlışlıkla çalışır. Yazılma şekli, DateAdd sözdiziminin (aralık, tarih, artış) olduğu gibidir, ancak değildir. (Aralık, artış, tarih). Bir tarihi ayın ilkine kısaltmaya çalıştığımda tökezledim: SELECT DATEADD (m, 0, DATEDIFF (m, 0, GETDATE ())) çalışmıyor, ancak DATEADD (m, DATEDIFF (m, 0, GETDATE ()), 0) yapar. En azından 2008R2'de gördüğüm şey bu.
Kelly Cline

1
@ 2008R2'deki Kelly, neden sadece değil cast(getdate() as date)?
Joel Coehoorn

2
Onlar hepsi bir datetime sütun üzerinde çalışır. getdate()İşte tarih-saat kaynağınız için bir stand-in.
Joel Coehoorn

44

Yalnızca SQL Server 2008 için

CAST(@SomeDateTime AS Date) 

Sonra isterseniz datetime geri döndürün

CAST(CAST(@SomeDateTime AS Date) As datetime)

İyi nokta: Hala 2005'teyim ve 2008 için bu muhtemelen yeni "doğru" yol ve hatta "hızlı" yolun performansıyla bile eşleşebilir.
Joel Coehoorn

1
Bu yeni yolun performansı "hızlı" yoldan bile daha hızlıdır.
ErikE

21

Sadece daha eksiksiz bir cevap uğruna, tarih bölümlerinden herhangi birine kısmak ve dakikaları dahil etmek için bir çalışma yolu (kısaltmak için tarihle değiştirin GETDATE()).

Bu sadece dd(gün) değil, tarih bölümlerinden herhangi birini kullanabileceğiniz kabul edilen cevaptan farklıdır ( buraya bakın ):

dateadd(minute, datediff(minute, 0, GETDATE()), 0)

Yukarıdaki ifadede, bunun 0bir yılın başında sabit bir tarih olduğunu unutmayın (1900-01-01). Saniye veya milisaniye gibi daha küçük parçalara kısalmanız gerekiyorsa, taşmayı önlemek için kısaltılacak tarihe daha yakın olan sabit bir tarih almanız gerekir.


1
Bu korkunç bir şekilde yardımcı oldu. Tarihin tamamını tam günden daha düşük bir yerde kısaltmanın bir yolunu aradım.
Michael - Clay Shirky

1
@Michael, geri bildiriminiz için teşekkürler, size yardımcı olduğunu bilmek güzel!
Lucero

1
+1 daha fazla oy vermeli, seçilen cevabı genişleten harika bir cevap.
jtate

1
İnternetin bildiği gibi, tam tarih bölümü dönemleriyle sınırlı olmanız gerekmez. İşte tamsayı bölümünü kullanan 15 dakikalık aralıklar için bir örnek:dateadd(minute, datediff(minute, 0, GETDATE()) / 15 * 15, 0)
Michael - Clay Shirky

7

Bunu yapmak zorunda olduğumda web'de bulduğum pasaj:

 dateadd(dd,0, datediff(dd,0, YOURDATE))
 e.g.
 dateadd(dd,0, datediff(dd,0, getDate()))

2005'deyim, ama 2008'in bunun için yeni bir işlevi olduğunu düşündüm ??
KM.

2
Temiz! Ben dateparts bölme ve onları bir araya getirmek için dize işleme kullanarak başvurdunuz. Alakalı olmayabilir, ancak SQL2008'de zaman öğesi olmadan salt bir tarih veri türü vardır.
Frans

1
Ve DateAdd işlenenlerinin karışık olduğunu unutmayın DateAdd(dd, DateDiff(...), 0). Dikkatli değilseniz bu sizi ısırabilir.
ErikE

1

SQl 2005'te trunc_date işleviniz bu şekilde yazılabilir.

(1)

CREATE FUNCTION trunc_date(@date DATETIME)
RETURNS DATETIME
AS
BEGIN
    CAST(FLOOR( CAST( @date AS FLOAT ) )AS DATETIME)
END

İlk yöntem çok daha temiz. Son CAST () dahil olmak üzere yalnızca 3 yöntem çağrısı kullanır ve otomatik bir artı olan dize birleştirmesi gerçekleştirmez. Dahası, burada büyük tip dökümler yoktur. Tarih / Saat damgalarının temsil edilebileceğini hayal edebiliyorsanız, tarihlerden sayılara ve tarihlere geri dönüş yapmak oldukça kolay bir işlemdir.

(2)

CREATE FUNCTION trunc_date(@date DATETIME)
RETURNS DATETIME
AS
BEGIN
      SELECT CONVERT(varchar, @date,112)
END

Microsoft'un datIME (2) veya (3) uygulamalarıyla ilgili endişeleriniz varsa sorun olmayabilir.

(3)

CREATE FUNCTION trunc_date(@date DATETIME)
RETURNS DATETIME
AS
BEGIN
SELECT CAST((STR( YEAR( @date ) ) + '/' +STR( MONTH( @date ) ) + '/' +STR( DAY(@date ) )
) AS DATETIME
END

Üçüncü olarak, daha ayrıntılı yöntem. Bu, tarihi yıl, ay ve gün bölümlerine ayırmayı, bunları "yyyy / aa / gg" biçiminde bir araya getirmeyi ve ardından bir tarihe dönüştürmeyi gerektirir. Bu yöntem, son CAST () dahil 7 yöntem çağrısını içerir, dize birleştirmesinden bahsetmez.


1
CONVERT(DATE, <yourdatetime>) or CONVERT(DATE, GetDate()) or CONVERT(DATE, CURRENT_TIMESTAMP)


0

Buraya DATETIME alanını bir günden daha az bir şeye (örneğin her dakika) kısaltmanın bir yolunu arayanlar için bunu kullanabilirsiniz:

SELECT CAST(FLOOR(CAST(GETDATE() AS FLOAT)) + (FLOOR((CAST(GETDATE() AS FLOAT) - FLOOR(CAST(GETDATE() AS FLOAT))) * 1440.0) + (3.0/86400000.0)) / 1440.0 AS DATETIME)

bugün 2010-11-26 14:54:43.123olsaydı bu geri dönecekti 2010-11-26 14:54:00.000.

Değer verdiği aralığı değiştirmek için 1440.0'ı bir gün içindeki aralık sayısı ile değiştirin, örneğin:

24hrs          =   24.0  (for every hour)
24hrs / 0.5hrs =   48.0  (for every half hour)
24hrs / (1/60) = 1440.0  (for every minute)

( .0Bir şamandıraya dolaylı olarak dökmek için her zaman sonuna bir a koyun .)


Merak olanlar için (3.0/86400000)benim hesaplamada içindir SQL Server 2005 döküm görünmüyor FLOATiçin DATETIMEbu onu döşeme önce 3 milisaniye ekler böylece, doğru.


1
Yine de kayan nokta hassasiyeti sınırları nedeniyle yuvarlama hatalarına dikkat edin ... Ayrıca, bu datetime2veri türüyle çalışmaz .
Lucero

Saat için SELECT DATEADD (saat, DATEDIFF (saat, 0, GETDATE ()), 0) da çalışır. Dakika da, ancak İkinci bir taşmaya neden olur.
Kelly Cline

Kayan ve datetime dönme özelliği düzgün çalışmaz .
ErikE

0

Bu sorgu size trunc(sysdate)Oracle'da eşdeğer bir sonuç vermelidir .

SELECT  * 
FROM    your_table
WHERE   CONVERT(varchar(12), your_column_name, 101)
      = CONVERT(varchar(12), GETDATE(), 101)

Bu yardımcı olur umarım!


0

Tarihi using Substringdatetime değişkeninden ayıklayabilirsiniz ve datetime öğesine geri döndürmek zaman bölümünü yoksayar.

declare @SomeDate datetime = '2009-05-28 16:30:22'
SELECT cast(substring(convert(varchar(12),@SomeDate,111),0,12) as Datetime) 

Ayrıca, datetime değişkeninin parçalarına erişebilir ve bunları kesilmiş bir tarihle birleştirebilirsiniz.

SELECT cast(DATENAME(year, @Somedate) + '-' + 
       Convert(varchar(2),DATEPART(month, @Somedate)) + '-' +
       DATENAME(day, @Somedate) 
       as datetime)

0

Oracle:

TRUNC(SYSDATE, 'MONTH')

SQL Server:

DATEADD(DAY, - DATEPART(DAY, DateField) + 1, DateField)

Benzer şekilde bir tarihten sonraki dakikaları veya saatleri kısaltmak için de kullanılabilir.



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.