web-dev-qa-db-ja.com

SQL Serverで時間を比較するにはどうすればよいですか?

SQLクエリのdatetimeフィールドで時間を比較しようとしていますが、正しいかどうかはわかりません。日付の部分を比較するのではなく、時間の部分だけを比較したいと思います。

私はこれをやっています:

SELECT timeEvent 
FROM tbEvents 
WHERE convert(datetime, startHour, 8) >= convert(datetime, @startHour, 8)

それが正しいか?

08:00:0007:30:00よりも小さいか大きいかを知る必要があり、日付を比較したくないので、time部分。

ありがとう!

58
AndreMiranda

比較は機能しますが、日付が各行の文字列に変換されるため、時間がかかります。 2つの時間部分を効率的に比較するには、次を試してください。

declare @first datetime
set @first = '2009-04-30 19:47:16.123'
declare @second datetime
set @second = '2009-04-10 19:47:16.123'

select (cast(@first as float) - floor(cast(@first as float))) -
       (cast(@second as float) - floor(cast(@second as float)))
       as Difference

長い説明:SQLサーバーの日付は浮動小数点数として保存されます。小数点の前の数字は日付を表します。小数点の後の数字は時刻を表します。

日付の例を次に示します。

declare @mydate datetime
set @mydate = '2009-04-30 19:47:16.123'

それをフロートに変換しましょう:

declare @myfloat float
set @myfloat = cast(@mydate as float)
select @myfloat
-- Shows 39931,8244921682

次に、数字の後の部分、つまり時間を取ります:

set @myfloat = @myfloat - floor(@myfloat) 
select @myfloat
-- Shows 0,824492168212601

日時に変換し直します:

declare @mytime datetime
set @mytime = convert(datetime,@myfloat)
select @mytime
-- Shows 1900-01-01 19:47:16.123

1900-01-01は単なる「ゼロ」の日付です。 convertを使用して時刻部分を表示できます。たとえば、フォーマット108を指定します。これは時刻です。

select convert(varchar(32),@mytime,108)
-- Shows 19:47:16

Datetimeとfloatの間の変換は、基本的に同じ方法で保存されるため、非常に高速です。

75
Andomar
_convert(varchar(5), thedate, 108) between @leftTime and @rightTime
_

説明:

varchar(5)がある場合は、_HH:mm_を取得します

varchar(8)がある場合は、_HH:mm ss_を取得します

108は、SQL日付から時刻のみを取得します

_@leftTime_と_@rightTime_は比較する2つの変数です

19
Iralda Mitro

SQL Server 2008を使用している場合、これを行うことができます。

WHERE CONVERT(time(0), startHour) >= CONVERT(time(0), @startTime)

完全なテストは次のとおりです。

DECLARE @tbEvents TABLE (
    timeEvent   int      IDENTITY,
    startHour   datetime
)

INSERT INTO @tbEvents (startHour) SELECT DATEADD(hh, 0, GETDATE())
INSERT INTO @tbEvents (startHour) SELECT DATEADD(hh, 1, GETDATE())
INSERT INTO @tbEvents (startHour) SELECT DATEADD(hh, 2, GETDATE())
INSERT INTO @tbEvents (startHour) SELECT DATEADD(hh, 3, GETDATE())
INSERT INTO @tbEvents (startHour) SELECT DATEADD(hh, 4, GETDATE())
INSERT INTO @tbEvents (startHour) SELECT DATEADD(hh, 5, GETDATE())

--SELECT * FROM @tbEvents

DECLARE @startTime  datetime

SET @startTime = DATEADD(mi, 65, GETDATE())

SELECT
    timeEvent,
    CONVERT(time(0), startHour)  AS 'startHour',
    CONVERT(time(0), @startTime) AS '@startTime'
FROM @tbEvents
WHERE CONVERT(time(0), startHour) >= CONVERT(time(0), @startTime)
12
Rob Garrison
if (cast('2012-06-20 23:49:14.363' as time) between 
    cast('2012-06-20 23:49:14.363' as time) and 
    cast('2012-06-20 23:49:14.363' as time))
4
Edgardo Correa

Floatを使用しても機能しません。

DECLARE @t1 datetime, @t2 datetime
SELECT @t1 = '19000101 23:55:00', @t2 = '20001102 23:55:00'
SELECT CAST(@t1 as float) - floor(CAST(@t1 as float)), CAST(@t2 as float) - floor(CAST(@t2 as float))

値が同じではないことがわかります(SQL Server 2005)。このメソッドを使用して、現在の時刻を23:55:00から00:05:00の間に比較する深夜(完全なメソッドの詳細があります)前後の時刻を確認したかったのです。

3
ronmurp

変換日時を、トリックを実行する時間に変更するだけです:

SELECT timeEvent 
FROM tbEvents 
WHERE convert(time, startHour) >= convert(time, @startHour)
3
Yi Zhang

これまでのソリューションで指摘した1つの(おそらく小さな)問題は、比較を処理するためにすべての関数呼び出しが必要なように見えることです。これは、クエリエンジンがフルテーブルスキャンを実行して、目的の行を探す必要があり、インデックスを使用できないことを意味します。テーブルが特に大きくならない場合、これはおそらく悪影響を及ぼさないでしょう(そして、この答えを喜んで無視することができます)。

一方、テーブルが非常に大きくなると、クエリのパフォーマンスが低下する可能性があります。

日付の部分を比較したくないと言っていましたが、datetime列に実際の日付が保存されていますか、それとも時刻のみを保存するために使用していますか?後者の場合、単純な比較演算子を使用できます。これにより、両方のCPU使用量が削減され、クエリエンジンは統計とインデックス(存在する場合)を使用してクエリを最適化できます。

ただし、イベントの日付と時刻の両方を格納するためにdatetime列が使用されている場合、これは明らかに機能しません。この場合、アプリとテーブル構造を変更できる場合は、日付と時刻を2つの別々のdatetime列に分離するか、ソーステーブルのすべての(関連する)列を選択するインデックス付きビューを作成し、検索する時間要素(これを計算するために以前の回答のいずれかを使用)-代わりにビューを照会するようにアプリを変更します。

3
Jason Musgrove

Datepart関数を使用: [〜#〜] datepart [〜#〜] (datepart、date)

例えば#

SELECT DatePart(@YourVar、hh)* 60)+ DatePart(@YourVar、mi)* 60)

これにより、1日の合計時間が分単位で表示され、より簡単に比較できます。

日付が同じになる場合は、DateDiffを使用できます。そうでない場合は、上記のように日付を削除する必要があります

2
littlechris

他の回答に追加:

日時から日付をトリムする関数を作成できます

CREATE FUNCTION dbo.f_trimdate (@dat datetime) RETURNS DATETIME AS BEGIN
    RETURN CONVERT(DATETIME, CONVERT(FLOAT, @dat) - CONVERT(INT, @dat))
END

したがって、この:

DECLARE @dat DATETIME
SELECT @dat = '20080201 02:25:46.000'
SELECT dbo.f_trimdate(@dat)

1900-01-01 02:25:46.0​​00を返します

Datetimeの2つの変数を作成し、比較する必要がある日付の時間のみを設定できます。

declare  @date1 datetime;
declare  @date2 datetime;

select   @date1 = CONVERT(varchar(20),CONVERT(datetime, '2011-02-11 08:00:00'), 114)
select   @date2 = CONVERT(varchar(20),GETDATE(), 114)

日付は「1900-01-01」になり、比較できます

if @date1 <= @date2
   print '@date1 less then @date2'
else
   print '@date1 more then @date2'
2
Renato Bezerra
SELECT timeEvent 
  FROM tbEvents 
 WHERE CONVERT(VARCHAR,startHour,108) >= '01:01:01'

これにより、SQL Serverは、スタイル108( "hh:mm:ss")を使用して現在の日付/時刻をvarcharに変換します。また、必要に応じて別の変換する「01:01:01」を置き換えることもできます。

1
northpole

DATEPART('hour', datetime)を使用したいと思います。

参照はこちら:

http://msdn.Microsoft.com/en-us/library/ms174420.aspx

1
Paul Sonier

ストレージ内部に依存するのは好きではありません(datetimeは整数=日、小数=時間の浮動小数点数です)が、答えはJhonny D. Canoと同じです。これは、私が知っているすべてのdb開発者が行う方法です。絶対に文字列に変換しません。 float/intとしての処理を避ける必要がある場合、最良のオプションはDatePart()で時間/分/秒/ミリ秒を引き出すことです。

1
ahains

StartHour列と@startHour変数はどちらもDATETIMEであると想定しています。その場合、文字列に変換する必要があります。

SELECT timeEvent
FROM tbEvents
WHERE convert(VARCHAR(8), startHour, 8) >= convert(VARCHAR(8), @startHour, 8)
0
Chris Shaffer

@ronmurpは有効な懸念を引き起こします-キャスト/フロアアプローチは同時に異なる値を返します。 @littlechrisによる回答の行に沿って、分、秒、ミリ秒のコンポーネントを持つ時間を解決するより一般的なソリューションでは、この関数を使用して、1日の始まりからミリ秒数をカウントできます。

Create Function [dbo].[MsFromStartOfDay] ( @DateTime datetime )
Returns int
As
  Begin
      Return (
               ( Datepart( ms , @DateTime ) ) +
               ( Datepart( ss , @DateTime ) * 1000 ) +
               ( Datepart( mi , @DateTime ) * 1000 * 60 ) +
               ( Datepart( hh , @DateTime ) * 1000 * 60 * 60 )
              )
  End

同じ時刻で2つの異なる日付に対して同じintを返すことを確認しました

declare @first datetime
set @first = '1900-01-01 23:59:39.090'
declare @second datetime
set @second = '2000-11-02 23:56:39.090'
Select dbo.MsFromStartOfDay( @first )
Select dbo.MsFromStartOfDay( @second )

この解決策は、常に期待するintを返すとは限りません。たとえば、SQL 2005で以下を試してください。「556」ではなく「557」で終わるintが返されます。

set @first = '1900-01-01 23:59:39.556'
set @second = '2000-11-02 23:56:39.556'

これは、DateTimeがfloatとして格納されているという性質に関係していると思います。ただし、2つの数値を比較することはできます。そして、DateTime.Now()を使用して.NETでキャプチャされ、SQLに保存されたDateTimeの「実際の」データセットでこのアプローチを使用すると、計算が正確であることがわかりました。

0
SFun28

以下のクエリは日付の時間を提供します

select DateAdd(day,-DateDiff(day,0,YourDateTime),YourDateTime) As NewTime from Table
0
Darsh