SQLクエリのdatetimeフィールドで時間を比較しようとしていますが、正しいかどうかはわかりません。日付の部分を比較するのではなく、時間の部分だけを比較したいと思います。
私はこれをやっています:
SELECT timeEvent
FROM tbEvents
WHERE convert(datetime, startHour, 8) >= convert(datetime, @startHour, 8)
それが正しいか?
08:00:00
が07:30:00
よりも小さいか大きいかを知る必要があり、日付を比較したくないので、time部分。
ありがとう!
比較は機能しますが、日付が各行の文字列に変換されるため、時間がかかります。 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の間の変換は、基本的に同じ方法で保存されるため、非常に高速です。
_convert(varchar(5), thedate, 108) between @leftTime and @rightTime
_
説明:
varchar(5)
がある場合は、_HH:mm
_を取得します
varchar(8)
がある場合は、_HH:mm ss
_を取得します
108は、SQL日付から時刻のみを取得します
_@leftTime
_と_@rightTime
_は比較する2つの変数です
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)
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))
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の間に比較する深夜(完全なメソッドの詳細があります)前後の時刻を確認したかったのです。
変換日時を、トリックを実行する時間に変更するだけです:
SELECT timeEvent
FROM tbEvents
WHERE convert(time, startHour) >= convert(time, @startHour)
これまでのソリューションで指摘した1つの(おそらく小さな)問題は、比較を処理するためにすべての関数呼び出しが必要なように見えることです。これは、クエリエンジンがフルテーブルスキャンを実行して、目的の行を探す必要があり、インデックスを使用できないことを意味します。テーブルが特に大きくならない場合、これはおそらく悪影響を及ぼさないでしょう(そして、この答えを喜んで無視することができます)。
一方、テーブルが非常に大きくなると、クエリのパフォーマンスが低下する可能性があります。
日付の部分を比較したくないと言っていましたが、datetime列に実際の日付が保存されていますか、それとも時刻のみを保存するために使用していますか?後者の場合、単純な比較演算子を使用できます。これにより、両方のCPU使用量が削減され、クエリエンジンは統計とインデックス(存在する場合)を使用してクエリを最適化できます。
ただし、イベントの日付と時刻の両方を格納するためにdatetime列が使用されている場合、これは明らかに機能しません。この場合、アプリとテーブル構造を変更できる場合は、日付と時刻を2つの別々のdatetime列に分離するか、ソーステーブルのすべての(関連する)列を選択するインデックス付きビューを作成し、検索する時間要素(これを計算するために以前の回答のいずれかを使用)-代わりにビューを照会するようにアプリを変更します。
Datepart関数を使用: [〜#〜] datepart [〜#〜] (datepart、date)
例えば#
SELECT DatePart(@YourVar、hh)* 60)+ DatePart(@YourVar、mi)* 60)
これにより、1日の合計時間が分単位で表示され、より簡単に比較できます。
日付が同じになる場合は、DateDiffを使用できます。そうでない場合は、上記のように日付を削除する必要があります
他の回答に追加:
日時から日付をトリムする関数を作成できます
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.000を返します
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'
SELECT timeEvent
FROM tbEvents
WHERE CONVERT(VARCHAR,startHour,108) >= '01:01:01'
これにより、SQL Serverは、スタイル108( "hh:mm:ss")を使用して現在の日付/時刻をvarcharに変換します。また、必要に応じて別の変換する「01:01:01」を置き換えることもできます。
ストレージ内部に依存するのは好きではありません(datetimeは整数=日、小数=時間の浮動小数点数です)が、答えはJhonny D. Canoと同じです。これは、私が知っているすべてのdb開発者が行う方法です。絶対に文字列に変換しません。 float/intとしての処理を避ける必要がある場合、最良のオプションはDatePart()で時間/分/秒/ミリ秒を引き出すことです。
StartHour列と@startHour変数はどちらもDATETIMEであると想定しています。その場合、文字列に変換する必要があります。
SELECT timeEvent
FROM tbEvents
WHERE convert(VARCHAR(8), startHour, 8) >= convert(VARCHAR(8), @startHour, 8)
@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の「実際の」データセットでこのアプローチを使用すると、計算が正確であることがわかりました。
以下のクエリは日付の時間を提供します
select DateAdd(day,-DateDiff(day,0,YourDateTime),YourDateTime) As NewTime from Table