web-dev-qa-db-ja.com

HH:MM:SS形式のDATEDIFF

開始時間と終了時間のデータを前提として、合計の長さを時間、分、秒、および平均の長さで計算する必要があります。

たとえば、結果は45:15:10のようになります。これは45時間15分10秒を意味し、30:07は30分07秒を意味します。

SQL Server 2008 R2を使用していますが、時間が24:59:59を超えると、変換に失敗しました。私がこれをどのように行うことができるかについてのアイデアはありますか?

参考までに、表の列はIdStartDateTimeEndDateTimeなどです。月の記録数、合計を含む月次レポートを作成する必要があります。これらのレコードの長さ、および平均の長さ。これらすべてを実行する簡単な方法があるかどうか知りたいのですが。

14
user1671731

timeに変換するべきではありません。これは、期間や間隔ではなく、単一の24時間制で特定の時点を保存することを目的としています(24時間未満に制限されている場合でも、明らかにあなたのデータはそうではありません)。代わりに、必要な最小間隔(この場合は秒)でdatediffを取得し、数学と文字列の操作を実行して、必要な出力形式で表示することができます(秒をアプリケーションに返すか、レポートツールを使用して、この作業を実行してもらいます)。

DECLARE @d TABLE
(
  id INT IDENTITY(1,1), 
  StartDateTime DATETIME, 
  EndDateTime DATETIME
);

INSERT @d(StartDateTime, EndDateTime) VALUES 
(DATEADD(DAY, -2, GETDATE()), DATEADD(MINUTE, 15, GETDATE())),
(GETDATE()                  , DATEADD(MINUTE, 22, GETDATE())),
(DATEADD(DAY, -1, GETDATE()), DATEADD(MINUTE,  5, GETDATE())),
(DATEADD(DAY, -4, GETDATE()), DATEADD(SECOND, 14, GETDATE()));

;WITH x AS (SELECT id, StartDateTime, EndDateTime, 
  d = DATEDIFF(SECOND, StartDateTime, EndDateTime),
  a = AVG(DATEDIFF(SECOND, StartDateTime, EndDateTime)) OVER()
  FROM @d
)
SELECT id, StartDateTime, EndDateTime,
  [delta_HH:MM:SS] = CONVERT(VARCHAR(5), d/60/60)
  + ':' + RIGHT('0' + CONVERT(VARCHAR(2), d/60%60), 2)
  + ':' + RIGHT('0' + CONVERT(VARCHAR(2), d % 60), 2),
  [avg_HH:MM:SS] = CONVERT(VARCHAR(5), a/60/60)
  + ':' + RIGHT('0' + CONVERT(VARCHAR(2), a/60%60), 2)
  + ':' + RIGHT('0' + CONVERT(VARCHAR(2), a % 60), 2)
FROM x;

結果:

id  StartDateTime        EndDateTime          delta_HH:MM:SS  avg_HH:MM:SS
--  -------------------  -------------------  --------------  ------------
1   2013-01-19 14:24:46  2013-01-21 14:39:46  48:15:00        42:10:33
2   2013-01-21 14:24:46  2013-01-21 14:46:46   0:22:00        42:10:33
3   2013-01-20 14:24:46  2013-01-21 14:29:46  24:05:00        42:10:33
4   2013-01-17 14:24:46  2013-01-21 14:25:00  96:00:14        42:10:33

デルタが1時間未満の場合、MM:SSだけが表示されないため、これは正確には要求したものではありません。簡単なCASE式で調整できます。

;WITH x AS (SELECT id, StartDateTime, EndDateTime, 
  d = DATEDIFF(SECOND, StartDateTime, EndDateTime),
  a = AVG(DATEDIFF(SECOND, StartDateTime, EndDateTime)) OVER()
  FROM @d
)
SELECT id, StartDateTime, EndDateTime,
  [delta_HH:MM:SS] = CASE WHEN d >= 3600 THEN 
    CONVERT(VARCHAR(5), d/60/60) + ':' ELSE '' END
  + RIGHT('0' + CONVERT(VARCHAR(2), d/60%60), 2)
  + ':' + RIGHT('0' + CONVERT(VARCHAR(2), d % 60), 2),
  [avg_HH:MM:SS] = CASE WHEN a >= 3600 THEN 
    CONVERT(VARCHAR(5), a/60/60) + ':' ELSE '' END
  + RIGHT('0' + CONVERT(VARCHAR(2), a/60%60), 2)
  + ':' + RIGHT('0' + CONVERT(VARCHAR(2), a % 60), 2)
FROM x;

このクエリは、上記の結果の2行目のデルタ列を0:22:00から22:00に変更します。

10
Aaron Bertrand
SELECT CONVERT(time, 
               DATEADD(mcs, 
                       DATEDIFF(mcs, 
                                '2007-05-07 09:53:00.0273335', 
                                '2007-05-07 09:53:01.0376635'), 
                       CAST('1900-01-01 00:00:00.0000000' as datetime2)
                      )
              )
3
Avinash Reddy

差が大きすぎるとエラーで終わる可能性があるため、Avinashの回答を少し変更しました。 HH:mm:ssのみが必要な場合は、次のように秒レベルで区別するだけで十分です。

SELECT CONVERT(time, 
  DATEADD(s, 
    DATEDIFF(s, 
      '2018-01-07 09:53:00', 
      '2018-01-07 11:53:01'), 
     CAST('1900-01-01 00:00:00.0000000' as datetime2)
   )
)
2

SQL SERVER 2012以降、DATEDIFF関数を使用する必要はありません。 FORMAT関数を使用して、目的を達成できます。

SELECT
    FORMAT(CONVERT(TIME, [appoitment].[Start] - [appointment].[End]), N'hh\:mm') AS 'Duration'
FROM
    [tblAppointment] (NOLOCK)
1
Bruno Leitão

平均を取りたい場合、最良のアプローチは秒または1日の端数に変換することです。 SQL Serverでは、次のようなことができるため、日数が便利です。

select avg(cast(endtime - starttime) as float)
from t

リバースキャストを使用して、それをdatetimeに戻すことができます。

select cast(avg(cast(endtime - starttime as float) as datetime)
from t

必要な形式で時間を取得するための算術。 。 。それは苦痛です。最終的な形式に日を含めて、以下を使用することを検討してください。

select right(convert(varchar(255), <val>, 120), 10)

24時間を超える時間を取得するには、次の方法があります。

select cast(floor(cast(<val> as float)*24) as varchar(255))+right(convert(varchar(255), <val>, 120), 6)

convertを分と秒に使用します。これには、左側に0を付ける必要があります。次に、時間を個別の値として追加します。

1
Gordon Linoff

オーバーフローを回避し、日数を含めて出力にミリ秒まで含めることができる方法:

DECLARE @startDate AS DATETIME = '2018-06-01 14:20:02.100'
DECLARE @endDate AS DATETIME = '2018-06-02 15:23:09.000'
SELECT CAST(DATEDIFF(day,'1900-01-01', @endDate - @startDate) AS VARCHAR) +  'd ' + CONVERT(varchar(22), @endDate - @startDate, 114)

上記は戻ります

1d 01:03:06:900

そして、もちろん、あなたはあなたの選んだフォーマットを使うことができます

SQLは、MIN日付に関連する新しい日時を出力する日時減算をサポートします(たとえば、1900-01-01、おそらくいくつかのシステム変数からこの値を取得できます)DATEDIFFは「日付部分の境界」ごとに1をカウントするため、これはDATEDIFFよりもうまく機能します経過時間がデータパーツ全体より短い場合でも、「交差」。この方法のもう1つの優れた点は、日付形式の変換を使用できることです。