SQL Serverで日時を切り捨てる方法を教えてください。


280

SQL Server 2008で日時の値を切り捨てる(時間、分、秒を削除する)ための最良の方法は何ですか?

例えば:

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

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

回答:


494

これは数年後でも頻繁に追加の投票を集め続けているため、最新バージョンのSQL Serverに合わせて更新する必要があります。SQL Server 2008以降の場合、それは簡単です。

cast(getDate() As Date)

下部近くの最後の3つの段落も引き続き適用されることに注意してください。多くの場合、最初の段階でキャストを回避する方法を見つける必要があります。

しかし、これを達成する他の方法もあります。ここでは最も一般的です。

正しい方法(SQL Server 2008以降の新機能):

cast(getdate() As Date)

正しい方法(古い):

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

これは現在は古いですが、月、分、時間、または年の最初の瞬間などの他の時点にも簡単に適応できるため、知っておく価値はあります。

この正しい方法は、ansi標準の一部であり、動作することが保証されている文書化された関数を使用しますが、多少遅くなる場合があります。これは、0日から現在の日までの日数を検索し、その日数を0日目までさかのぼって追加することで機能します。日時の格納方法やロケールが何であっても機能します。

速い方法:

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

これは、日時列が8バイトのバイナリ値として格納されるため機能します。それらを浮動小数点数にキャストし、それらをフロアして端数を削除します。値を日時にキャストすると、値の時間部分はなくなります。それはすべて、複雑なロジックなしでビットシフトするだけで、非常に高速です。

これは実装の詳細に依存していることに注意してください。Microsoftは、自動サービスアップデートであっても、いつでも自由に変更できます。また、移植性もあまり高くありません。実際には、この実装がすぐに変更される可能性は非常に低いですが、それを使用することを選択した場合の危険性を認識することは依然として重要です。日付としてキャストできるようになったので、ほとんど必要ありません。

間違った方法:

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

間違った方法は、文字列に変換し、文字列を切り捨て、日時に変換することによって機能します。これは間違っています。2つの理由があります。1)すべてのロケールで機能しない可能性があること、および2)これを実行するための最も遅い方法についてであり、少しだけではない。他のオプションよりも1桁か2倍遅いです。


更新これは最近いくつかの票を得ているので、これに追加したいと思います。これを投稿してから、SQL Serverが「正しい」方法と「速い」方法のパフォーマンスの違いを最適化するというかなり確かな証拠を見てきましたつまり、前者を支持する必要があります。

どちらの場合も、最初にこれを行う必要がないようにクエリ記述します。データベースでこの作業を行う必要があるのは非常にまれです。

ほとんどの場所で、データベースはすでにボトルネックになっています。一般に、パフォーマンスの向上のためにハードウェアを追加するのが最も費用がかかるサーバーであり、それらの追加を正しく行うのが最も難しいサーバーです(たとえば、メモリとディスクのバランスをとる必要があります)。また、技術的にもビジネスの観点からも、外部への拡張が最も困難です。データベースサーバーよりもWebサーバーまたはアプリケーションサーバーを追加する方が技術的にはるかに簡単であり、それが誤りであっても、IISまたはApacheのサーバーライセンスごとに$ 20,000以上を支払う必要はありません。

私がしようとしているポイントは、可能な限りアプリケーションレベルでこの作業を行う必要があるということです。唯一の挿入/更新時に維持され、または維持され、あなたが一日でグループに必要がある場合、あなたは今まで自分がSQL Serverで日時を切り捨て見つけなければならない時間があり、その場合でも、あなたはおそらく、計算列として設定し、余分な列を持っている必要がありますアプリケーションロジックで。このインデックスを壊す、CPU負荷の高い作業をデータベースから実行します。


6
私が実行したばかりのベンチマークによると、「高速な方法」は依然としてSQL 2008の最速の方法です
Sam Saffron

3
参考までに:stackoverflow.com/q/1177449/27535およびstackoverflow.com/q/133081/27535 dateadd / datediff "wins ..."。単一の変数の場合、もちろん問題はありません。列または100万行以上を計算したことを期待しています:-)
gbn

9
この「正しい」方法は誤って機能するだけです。記述方法は、DateAddの構文が(interval、date、increment)であるかのようですが、そうではありません。(間隔、増分、日付)です。月の最初に日付を切り詰めようとしたときに私はこれに遭遇しました:SELECT DATEADD(m、0、DATEDIFF(m、0、GETDATE()))は機能しませんが、SELECT DATEADD(m、DATEDIFF(m、 0、GETDATE())、0)は行います。少なくとも、これは2008R2で見られるものです。
Kelly Cline、2009

1
@Rellyの2008R2、なぜただではないのcast(getdate() as date)ですか?
Joel Coehoorn、2011年

2
それらはすべて日時列で機能します。getdate()ここにあなたが持っているかもしれないどんな日付時刻源のための代用もある。
Joel Coehoorn、2015

44

SQL Server 2008のみ

CAST(@SomeDateTime AS Date) 

次に、必要に応じてそれを日時にキャストします

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

良い点:私はまだ2005年なので、2008年はおそらくこれが新しい「正しい」方法であり、「速い」方法のパフォーマンスにさえ一致するかもしれません。
Joel Coehoorn、2009年

1
この新しい方法のパフォーマンスは、「高速」な方法よりもさらに高速です。
ErikE

21

より完全な答えを出すために、日付部分を切り捨てて分を含めるための有効な方法を次に示します(GETDATE()切り捨てる日付に置き換えます)。

これはdd、(日)だけでなく、任意の日付部分(ここを参照)を使用できるという点で、受け入れられた回答とは異なります。

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

上記の式で、0は年の初めの一定の日付(1900-01-01)であることに注意してください。秒やミリ秒などの小さな部分に切り捨てる必要がある場合は、オーバーフローを回避するために、切り捨てられる日付により近い一定の日付を取得する必要があります。


1
これはものすごく役に立ちました。終日より低い場所で日時を切り捨てる方法を探しました。
マイケル-クレイシャーキーは

1
@マイケル、フィードバックをありがとう、それがあなたを助けたことを知ってよかった!
Lucero

1
+1これにはより多くの投票が必要です。選択した回答を拡張する素晴らしい回答です。
jtate 2014

1
インターネットでわかるように、日付の完全な期間に制限する必要はありません。:ここでの例では、整数の除算を使用して15分間隔、のためだdateadd(minute, datediff(minute, 0, GETDATE()) / 15 * 15, 0)
マイケル-のクレイ・シャーキー

7

私がこれをしなければならなかったときに私がウェブで見つけたスニペットは:

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

私は2005年ですが、2008年には新しい機能がいくつかあると思いましたか?
和基。

2
きちんと!私は日付部分を分割し、文字列処理を使用してそれらを元に戻すことに頼っていたでしょう。関連性はないかもしれませんが、SQL2008には時刻要素のない純粋な日付のみのデータ型があります。
フランス、

1
また、DateAddオペランドが混同されていることに注意してくださいDateAdd(dd, DateDiff(...), 0)。あなたが注意しなければ、これはあなたを噛むことがあります。
ErikE 2013年

1

SQl 2005では、trunc_date関数は次のように記述できます。

(1)

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

最初の方法ははるかにクリーンです。最後のCAST()を含む3つのメソッド呼び出しのみを使用し、文字列の連結を実行しません。これは自動プラスです。さらに、ここには巨大な型キャストはありません。日付/時刻スタンプを表すことができると想像できる場合、日付から数値への変換と日付への変換はかなり簡単なプロセスです。

(2)

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

マイクロソフトの日時(2)または(3)の実装が心配な場合は、問題ないかもしれません。

(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

第三に、より冗長な方法です。これには、日付を年、月、日の部分に分割し、それらを「yyyy / mm / dd」形式でまとめて、日付にキャストし直す必要があります。このメソッドには、文字列の連結は言うまでもなく、最後のCAST()を含む7つのメソッド呼び出しが含まれます。


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


0

ここに来てDATETIMEフィールドを丸一日未満、たとえば毎分に切り捨てる方法を探している人は、これを使用できます。

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)

今日だったら2010-11-26 14:54:43.123、これは戻るでしょう2010-11-26 14:54:00.000

処理する間隔を変更するには、1440.0を1日の間隔の数に置き換えます。次に例を示します。

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

(常に.0フロートに暗黙的にキャストするには、最後にaを付けます。)


(3.0/86400000)SQL Server 2005は正確にキャストされFLOATていないように見えるので、計算に何が必要か疑問に思う方のために、DATETIMEフローリングする前に3ミリ秒を追加します。


1
ただし、浮動小数点の精度制限による丸め誤差に注意してください...また、これはdatetime2データ型では機能しません。
Lucero、

時間の場合、SELECT DATEADD(時間、DATEDIFF(時間、0、GETDATE())、0)も機能します。分もですが、秒はオーバーフローになります。
Kelly Cline、2009

float型にキャストしてdatetime型に戻すと、正しく機能しません
ErikE 2013年

0

このクエリによりtrunc(sysdate)、Oracle と同等の結果が得られます。

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

お役に立てれば!


0

またusing Substring、datetime変数から日付を抽出し、datetimeにキャストバックすると、時間部分が無視されます。

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

また、次のように、datetime変数の一部にアクセスして、切り捨てられた日付の構成要素にマージすることもできます。

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

0

Oracle:

TRUNC(SYSDATE, 'MONTH')

SQLサーバー:

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

日付から分または時間を切り捨てるために同様に使用できます。


0

あなたはこれを行うことができます(SQL 2008):

@SomeDateを宣言するdate = getdate()

select @SomeDate

2009-05-28


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