2009-04-30 14 views
49

日時フィールドの時刻をSQLクエリで比較しようとしていますが、それが正しいかどうかわかりません。私は日付部分、ちょうど時間部分を比較したくない。SQL Serverで時刻を比較するにはどうすればよいですか?

は、私はこれをやっている:それは正しい

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

ですか?

'08:00:00 'が'07:30:00'より小さいか大きいかを知る必要があるため、私はこれを尋ねています。

ありがとうございます!

+0

私は時間が他のものよりも大きい場合は、私が比較できるようにVARCHARに変換しなければならないのはなぜ?私はこの方法で文字列と文字列を比較しませんか? – AndreMiranda

+0

DateDiff関数はdatetimeフィールドを入力として受け入れます。 – Eric

答えて

69

を比較するには、2つの変数だけの時間を取得し、日付は各行の文字列に変換されます。 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' 

だがfloatに変換してみましょう:

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はちょうど "ゼロ"の日付です。あなただけの時間であるフォーマット例108のために指定して、変換して、時間の部分を表示することができます。日時とフロートの間

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

変換を彼らは基本的に同じ方法で保存されているので、かなり速いです。

+0

これはすばらしいです、ありがとう!私はvarcharの変換をたくさん行ってきましたが、これはより良い方法のように思えます(それを見てすぐには分かりませんが)。 – Alex

2

使用DATEPART関数:DATEPART(DATEPART、日付)

例えば#

SELECT DATEPART(@YourVar、HH)* 60)+ DATEPART(@YourVar、MI)* 60)

これにより、より簡単に比較できる合計時間を分単位で指定できます。

あなたの日付が同じであることを行っている場合は、そうでないあなたに、現在の日付/時刻を変換するために、これは、SQL Serverに指示します

0
SELECT timeEvent 
    FROM tbEvents 
WHERE CONVERT(VARCHAR,startHour,108) >= '01:01:01' 

上記のように日付を取り除く必要があります、DateDiff関数を使用することができますスタイル108を使用するvarchar。これは "hh:mm:ss"です。 '01:01:01'を置き換えることもできます。必要に応じて別の変換を行います。

0

私はあなたのstartHour列と@startHour変数が両方DATETIMEあると仮定しています。その場合、あなたは文字列に変換する必要があります。

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

Chris、時間を比較するにはなぜVARCHArに変換する必要がありますか?この方法では、私は文字列と文字列を比較しませんか? – AndreMiranda

+1

2つの理由 - 1)CONVERT()メソッドはある型から別の型に変換するためのものです。 DATETIMEをDATETIMEに変換すると、何も起こりません。 2)CONVERT()の3番目のパラメータ(8)は、文字列型に進むときにデータをフォーマットするためのコードです。 DATETIMEに変換するときには意味がありません。 –

2

は、他の回答に追加:

あなたはこのだから、日時から

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 2時25分46秒を返します。000

+0

INTラウンドにキャストすると、結果が必ずしも正確ではない場合があります。フロアは行く方法です – murki

+0

これがサンプルの理由です。日付の丸めで、時間フィールドだけで作業できます。あなたはそれを試しましたか? –

11

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) 
+0

ロブ、私は2005年を使用しています:-( – AndreMiranda

+0

おかげでロブ、 "DATEADD"は私が探していたものでした! – Neville

17
convert(varchar(5), thedate, 108) between @leftTime and @rightTime 

説明varchar(5)を取得すると、HH:mm

あなたはvarchar(8)を持っている場合は、HH:mm ss

108を得るには、SQLの日付から

@leftTime@rightTimeがあなたの比較は動作しますが、それはので、遅くなります

+0

それは私にも役立ちます:)。 –

1

私はストレージの内部構造に依存するのが大好きではありません(その日時は、整数=日数と分数=時間のフロートです)、私はJhonny D. Canoの答えと同じことをします。これは私が知っているすべてのdb開発者のやり方です。間違いなく文字列に変換しないでください。 float/intとして処理する必要がない場合は、DatePart()で時/分/秒/ミリ秒を引き出すことをお勧めします。

3

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

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

あなたは日付部分を比較したくないと述べましたが、実際の日付はdatetime列に格納されているのですか、それとも時間だけを保存するために使用していますか?後者の場合、単純な比較演算子を使用できます。これにより、両方のCPU使用率が低下し、クエリエンジンが統計とインデックス(存在する場合)を使用してクエリを最適化できるようになります。

ただし、datetime列がイベントの日時を格納するために使用されている場合は、明らかに動作しません。この場合、アプリケーションとテーブル構造を変更できる場合は、日付と時刻を2つの別々のdatetime列に分けるか、ソース表のすべての(関連する)列を選択する索引付きビューを作成し、 (これを計算するために以前の答えのいずれかを使用します) - そして、代わりにビューを照会するようにアプリを変更してください。

3

浮動小数点の使用は機能しません。

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の間で現在の時刻を比較していた真夜中の時刻をチェックするためにこのメソッドを使いたいと思っていました。

1

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' 
0

はあなたの日付の時間を与える

select DateAdd(day,-DateDiff(day,0,YourDateTime),YourDateTime) As NewTime from Table 
4
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)) 
0

@ronmurpの昇給有効な懸念 - キャスト/フロアアプローチは同じ時間に異なる値を返します。 @littlechrisの答えに沿って、分、秒、ミリ秒の要素を持つ時間を解決するより一般的な解決策として、この関数を使用して、開始日からのミリ秒数をカウントすることができます。

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 

私はそれがこのソリューションはいつもあなたが期待する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の性質と関係があると思います。あなたはまだ2つの数字を比較することができます。 DateTime.Now()を使用して.NETに取り込まれ、SQLに格納されたDateTimeの「実際の」データセットでこの手法を使用した場合、計算が正確であることがわかりました。

+0

注 - このアプローチではパフォーマンスがあまり良くないようです – SFun28

2

ちょうどトリックを行う必要があり、時間に日時を変換する変更:

SELECT timeEvent 
FROM tbEvents 
WHERE convert(time, startHour) >= convert(time, @startHour) 
関連する問題