SQL Serverでdatetime2に日付と時刻を組み合わせる方法は?


48

次のコンポーネントを考える

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

それらを組み合わせてDATETIME2(7)価値のある結果を生成する最良の方法は何'2013-10-13 23:59:59.9999999'ですか?

動作しないものを以下にリストします。


SELECT @D + @T 

オペランドデータ型の日付は、追加演算子には無効です。


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

オペランドのデータ型datetime2は、add演算子には無効です。


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

datediff関数の結果、オーバーフローが発生しました。2つの日付/時刻インスタンスを分離する日付部分の数が多すぎます。精度の低い日付部分でdatediffを使用してみてください。

*を使用して、Azure SQL DatabaseおよびSQL Server 2016でオーバーフローを回避できますDATEDIFF_BIG


SELECT CAST(@D AS DATETIME) + @T 

日付と時刻のデータ型は、add演算子と互換性がありません。


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

結果を返しますが、精度を失います 2013-10-13 23:59:59.997

回答:


49

これは動作し、精度も維持しているようです:

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

変換した値(へ)日付部分がどこにある日付のデフォルト値と日時タイプである、(参照とコメント* MSDNのページ。)CASTDATETIME2(7)TIME(7)@TDATETIME2'1900-01-01'datetime2CASTCONVERT

* ...日付のみまたは時間コンポーネントのみを表す文字データがdatetimeまたはsmalldatetimeデータ型にキャストされる場合、未指定の時間コンポーネントは00:00:00.000に設定され、未指定の日付コンポーネントは1900-01-に設定されます01

間の日中の違い加えるつまり、残りの機能世話、および値を()。DATEADD()DATEDIFF()1900-01-01DATE@D

テスト:SQL-Fiddle


@Quandaryが気づいたように、上記の式はSQL Server によって決定論的ではないと見なされます。確定的な式が必要な場合、たとえばPERSISTED列に使用されるため、'19000101'**0or で置き換える必要があります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)、文字列の暗黙的な変換とDATETIME文字列から日時への変換が決定的であるため、決定的ではありません。


8

私はパーティーに遅れていますが、このアプローチは@ypercubeの答えに似ていますが、文字列変換(日付変換よりも高価になる可能性があります)を使用する必要性を回避し、決定論的であり、MSがこれを変更した場合は引き続き動作するはずです1900-01-01のデフォルトの日付値(おそらくこれを変更しない可能性があります):

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

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

原則は、時間値をdatetime2に変換してから日付に変換することにより、タイムアウトを削除してデフォルトの日付を割り当て、それから日付値でdatediffを実行して追加する日数を取得し、時間をdatetime2にキャストして、数日後。


「DATEDIFF(DAY、@T、@D)」の代わりに、「DATEDIFF(DAY、0、@D)」にする必要があります。結果は同じですが、混乱を避けるのに役立ちます。DateDiff(day、...)は引数を最小のint日数にキャストするため、@ Tはとにかく0に変換されます。
デニスゴリリック

5

SQL Server 2012以降には、DATETIME2FROMPARTS関数があります。この形式は次のとおりです。

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

指定されたサンプルデータの場合、これは

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

結果として

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

テンポラルデータ型から開始する場合はDATEPART()を使用して、または質問のサンプル値の作成に使用するテキストからパーツを取得できます。


0

最初の例を機能させないのはSQL Serverのバカです。

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
これをテストしましたか?動作しますか?言語設定の影響を受けますか?
ypercubeᵀᴹ

0

ここに着陸したとき、私は何か他のものを探していました。質問はかなり古いですが、最近のコメントと活動がいくつかあります。@Atarioが与えた答えに非常に似ている簡単な方法を共有したいと思いますが、少し短くなり、読みやすいかもしれません:

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

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

-3

withをDATEに切り捨てて切り捨て、次にDATETIMEに戻ってTIMEを追加できます

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

トリックは良いですが、上の質問には答えません。
user259412
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.