web-dev-qa-db-ja.com

SQLサーバーで日付をフロアリングする

SQL Serverでは、DATETIMEを秒/分/時間/日/年に「フロア」するにはどうすればよいですか?

2008-09-17 12:56:53.4の日付があるとしましょう。フローリングの出力は次のようになります。

  • 年:2008-01-01 00:00:00.000
  • 月:2008-09-01 00:00:00.000
  • 日:2008-09-17 00:00:00.000
  • 時間:2008-09-17 12:00:00.000
  • 分:2008-09-17 12:56:00.000
  • 2番目:2008-09-17 12:56:53.000
69
Portman

重要なのは、適切なSQLタイムスパン列挙とともに [〜#〜] dateadd [〜#〜] および [〜#〜] datediff [〜#〜] を使用することです。

declare @datetime datetime;
set @datetime = getdate();
select @datetime;
select dateadd(year,datediff(year,0,@datetime),0);
select dateadd(month,datediff(month,0,@datetime),0);
select dateadd(day,datediff(day,0,@datetime),0);
select dateadd(hour,datediff(hour,0,@datetime),0);
select dateadd(minute,datediff(minute,0,@datetime),0);
select dateadd(second,datediff(second,'2000-01-01',@datetime),'2000-01-01');
select dateadd(week,datediff(week,0,@datetime),-1); --Beginning of week is Sunday
select dateadd(week,datediff(week,0,@datetime),0); --Beginning of week is Monday

秒単位でフロアリングしている場合、0を使用すると、しばしば算術オーバーフローが発生することに注意してください。したがって、フロアしようとする日時よりも低いことが保証されている既知の値を選択してください。

96
Portman

SQL Serverでは、これを行うためのちょっとしたトリックがあります。

SELECT CAST(FLOOR(CAST(CURRENT_TIMESTAMP AS float)) AS DATETIME)

DateTimeをfloatにキャストします。floatは、Dateを整数部分として、Timeを経過した日の小数として表します。その小数部分を切り落とし、それをDateTimeにキャストすると、その日の初めに真夜中になります。

これは、おそらくすべてのDATEADDおよびDATEDIFFのものよりも効率的です。確かに入力する方がずっと簡単です。

28

Convert/Castソリューションを拡張して、Microsoft SQL Server 2008では次のことができます。

_cast(cast(getdate() as date) as datetime)
_

getdate()をdatetimeである列に置き換えるだけです。

この変換に関係する文字列はありません。

これは、アドホッククエリまたは更新では問題ありませんが、キー結合または頻繁に使用される処理の場合、処理内で変換を処理するか、適切なキーとデータを持つようにテーブルを再定義することをお勧めします。

2005年には、メッシエフロアを使用できます:cast(floor(cast(getdate() as float)) as datetime)

文字列変換も使用するとは思いませんが、実際の効率とアームチェアの推定値を比較することはできません。

12
Moe Cazzell

私は @ Portman's answer をフローリングの日付の参照として何年にもわたって使用し、その機能を便利な機能に移行しました。

私はそのパフォーマンスを主張せず、単にユーザー向けのツールとして提供しています。

この回答に賛成票を投じることにした場合は、 @ Portman's answer にも賛成票を投じてください。私のコードは彼の派生物です。

IF OBJECT_ID('fn_FloorDate') IS NOT NULL DROP FUNCTION fn_FloorDate
SET ANSI_NULLS OFF
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE FUNCTION [dbo].[fn_FloorDate] (
  @Date DATETIME = NULL,
  @DatePart VARCHAR(6) = 'day'
)
RETURNS DATETIME
AS
BEGIN
  IF (@Date IS NULL)
    SET @Date = GETDATE();

  RETURN
  CASE
    WHEN LOWER(@DatePart) = 'year' THEN DATEADD(YEAR, DATEDIFF(YEAR, 0, @Date), 0)
    WHEN LOWER(@DatePart) = 'month' THEN DATEADD(MONTH, DATEDIFF(MONTH, 0, @Date), 0)
    WHEN LOWER(@DatePart) = 'day' THEN DATEADD(DAY, DATEDIFF(DAY, 0, @Date), 0)
    WHEN LOWER(@DatePart) = 'hour' THEN DATEADD(HOUR, DATEDIFF(HOUR, 0, @Date), 0)
    WHEN LOWER(@DatePart) = 'minute' THEN DATEADD(MINUTE, DATEDIFF(MINUTE, 0, @Date), 0)
    WHEN LOWER(@DatePart) = 'second' THEN DATEADD(SECOND, DATEDIFF(SECOND, '2000-01-01', @Date), '2000-01-01')
    ELSE DATEADD(DAY, DATEDIFF(DAY, 0, @Date), 0)
  END;
END

使用法:

DECLARE @date DATETIME;
SET @date = '2008-09-17 12:56:53.430';

SELECT
  @date AS [Now],--2008-09-17 12:56:53.430
  dbo.fn_FloorDate(@date, 'year') AS [Year],--2008-01-01 00:00:00.000
  dbo.fn_FloorDate(default, default) AS [NoParams],--2013-11-05 00:00:00.000
  dbo.fn_FloorDate(@date, default) AS [ShouldBeDay],--2008-09-17 00:00:00.000
  dbo.fn_FloorDate(@date, 'month') AS [Month],--2008-09-01 00:00:00.000
  dbo.fn_FloorDate(@date, 'day') AS [Day],--2008-09-17 00:00:00.000
  dbo.fn_FloorDate(@date, 'hour') AS [Hour],--2008-09-17 12:00:00.000
  dbo.fn_FloorDate(@date, 'minute') AS [Minute],--2008-09-17 12:56:00.000
  dbo.fn_FloorDate(@date, 'second') AS [Second];--2008-09-17 12:56:53.000
6
Dan Atkinson

CONVERT() 関数も、使用するスタイルに応じてこれを実行できます。

2
Joel Coehoorn

残念なことに、Oracleではないか、trunc()またはto_char()を使用できます。

しかし、SQL Serverで同様の問題が発生し、CONVERT()およびDateDiff()メソッドを使用しました- here

1
typicalrunt

この猫の皮を剥ぐ方法はいくつかあります=)

select convert(datetime,convert(varchar,CURRENT_TIMESTAMP,101))
0
Sean

DateAddとDateDiffは、さまざまなタスクの実行に役立ちます。たとえば、任意の月の最終日を検索することも、前月または翌月の最終日を検索することもできます。

----Last Day of Previous Month
SELECT DATEADD(s,-1,DATEADD(mm, DATEDIFF(m,0,GETDATE()),0))
LastDay_PreviousMonth
----Last Day of Current Month
SELECT DATEADD(s,-1,DATEADD(mm, DATEDIFF(m,0,GETDATE())+1,0))
LastDay_CurrentMonth
----Last Day of Next Month
SELECT DATEADD(s,-1,DATEADD(mm, DATEDIFF(m,0,GETDATE())+2,0))
LastDay_NextMonth

ソース

0
pinaldave