SQL Server'da tarih ve saat datetime2 ile nasıl birleştirilir?


48

Aşağıdaki bileşenler göz önüne alındığında

DECLARE @D DATE = '2013-10-13'
DECLARE @T TIME(7) = '23:59:59.9999999'

Değerle DATETIME2(7)sonuç üretmek için bunları birleştirmenin en iyi yolu nedir '2013-10-13 23:59:59.9999999'?

Bazı şeyler yapma işi aşağıda listelenmiştir.


SELECT @D + @T 

İşlenen veri türü tarihi, işleç ekleme için geçersiz.


SELECT CAST(@D AS DATETIME2(7)) + @T 

İşlenen veri türü datetime2, ekleme işleci için geçersiz.


SELECT DATEADD(NANOSECOND,DATEDIFF(NANOSECOND,CAST('00:00:00.0000000' AS TIME),@T),@D)

Datediff işlevi taşmaya neden oldu. İki tarih / saat örneğini ayıran tarih bölümlerinin sayısı çok fazla. Datediff'i daha az kesin bir tarih noktasıyla kullanmayı deneyin.

* Kullanarak, Azure SQL Veritabanı ve SQL Server 2016'da taşma önlenebilir DATEDIFF_BIG.


SELECT CAST(@D AS DATETIME) + @T 

Tarih ve saat veri türleri add operatöründe uyumlu değil.


SELECT CAST(@D AS DATETIME) + CAST(@T AS DATETIME)

Bir sonuç verir, ancak hassaslığını yitirir 2013-10-13 23:59:59.997

Yanıtlar:


49

Bu da işe yarıyor ve hassasiyetini koruyor gibi görünüyor:

SELECT DATEADD(day, DATEDIFF(day,'19000101',@D), CAST(@T AS DATETIME2(7)))

CASTİçin DATETIME2(7)dönüştürür TIME(7)değer ( @Ta) DATETIME2tarih bölümü nerede '1900-01-01'tarihten varsayılan değeri ve tarih saat türleri olduğunu (bkz datetime2ve yorum * de CASTveCONVERT MSDN at yayınlanmaktadır.)

* ... Yalnızca tarih veya yalnızca zaman bileşenlerini temsil eden karakter verileri, tarih saatine veya küçük tarih saat veri türlerine dağıtıldığında, belirtilmeyen saat bileşeni 00: 00: 00.000 olarak ayarlanır ve belirtilmemiş tarih bileşeni 1900-01- olarak ayarlanır. 01 .

DATEADD()Ve DATEDIFF()dinlenme fonksiyonu almak bakımı, arasındaki gün farkı eklenerek yani 1900-01-01ve DATEdeğere ( @D).

Test at: SQL-Fiddle


@Quandary tarafından fark edildiği gibi , yukarıdaki ifade SQL Server tarafından deterministik değildir. Biz deterministik ifadesini istiyorsanız, bir için kullanılacak olması nedeniyle söylemek PERSISTEDsütununda, '19000101'** ihtiyaçlar tarafından değiştirilmesi 0ya CONVERT(DATE, '19000101', 112):

CREATE TABLE date_time
( d DATE NOT NULL,
  t TIME(7) NOT NULL,
  dt AS DATEADD(day, 
                DATEDIFF(day, CONVERT(DATE, '19000101', 112), d), 
                CAST(t AS DATETIME2(7))
               ) PERSISTED
) ;

**: DATEDIFF(day, '19000101', d)o kadar dizesinin bir örtük dönüştürme yaptığı gibi deterministik değildir DATETIMEve datetime dizelerden dönüşümler deterministik özgü stilleri kullanılmaktadır yalnızca.


8

Partiye geç kaldım ama bu yaklaşım, @ ypercube'un cevabına benzer şekilde , herhangi bir dize dönüşümünü kullanma ihtiyacını ortadan kaldırıyor (ki bu, tarih dönüşümlerinden daha pahalı olabilir), determinist ve MS'in değişmesi durumunda çalışmaya devam etmesi gerekiyor. 1900-01-01 arasındaki varsayılan tarih değeri (muhtemelen bunu değiştirmese bile):

DECLARE @D DATE = SYSUTCDATETIME()
, @T TIME = SYSUTCDATETIME();

SELECT DATEADD(DAY, DATEDIFF(DAY, @T, @D), CONVERT(DATETIME2, @T));

İlke, zaman değerini datetime2'ye ve ardından tarihe dönüştürerek zaman aşımına uğrar ve varsayılan tarihi atar, sonra ekleyeceğiniz günleri almak, zamanınızı datetime2'ye eklemek ve eklemek için tarih tarihinizle tarih tarihini değiştirirsiniz. günlerde.


"DATEDIFF (DAY, @T, @D)" yerine "DATEDIFF (DAY, 0, @D)" olmalıdır. Sonuç aynıdır, ancak karışıklığı önlemeye yardımcı olur. DateDiff (day, ...) bağımsız değişkenleri en düşük int gün sayısına gönderir, bu nedenle @T yine de 0'a dönüştürülür.
Dennis Gorelik

5

SQL Server 2012 ve daha üstü için DATETIME2FROMPARTS işlevi var. Bu forma sahiptir:

DATETIME2FROMPARTS(year, month, day, hour, minute, seconds, fractions, precision)

Verilen örnek veriler için bu olur

select Answer = DATETIME2FROMPARTS(2013, 10, 13, 23, 59, 59, 9999999, 7);

hangi sonuçlanır

Answer
---------------------------
2013-10-13 23:59:59.9999999

Temporal veri tiplerinden başlanırsa veya söz konusu örnek değerleri oluşturmak için kullanılan metinden başlanırsa, parçalar DATEPART () kullanılarak elde edilebilir .


0

SQL Server'ın ilk örneğinizin çalışmasına izin vermemek oldukça aptalca, ve bu da çok aptalca görünecek, ama…

select convert(datetime2, convert(nvarchar(max), @d) + ' ' + convert(nvarchar(max), @t));

0
SELECT mydate=CAST(CAST(@D AS nvarchar(max)) + ' ' + 
                   CAST(@T AS nvarchar (max)) 
              AS DATETIME2);

5
Bunu test ettin mi? Çalışıyor mu? Dil ayarlarından etkileniyor mu?
ypercubeᵀᴹ

0

Buraya indiğimde başka bir şey arıyordum. Bu soru oldukça eski, ancak yeni yorumlar ve aktiviteler var. @ Atario'nun verdiği cevaba çok benzeyen basit bir yöntem paylaşacağımı düşündüm, fakat biraz daha kısa ve bazıları okumayı daha kolay bulabilir:

declare @d date = '2013-10-13'
declare @t time(7) = '23:59:59.9999999'

select cast(concat(@d, ' ', @t) as datetime2(7))

-3

İle cast'i, kırpmak için DATE olarak, sonra da TIME eklemek için DATETIME olarak kesebilirsiniz.

select CAST( cast(getdate() as date) as DATETIME)  + CAST(getdate() as TIME)

İşin püf noktası iyi, ama en üstteki soruya cevap vermiyor.
user259412
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.