web-dev-qa-db-ja.com

カウント選択した行間の合計時間差

私のデータには、ID、ステータス、および時刻(hh:mm:ss)が含まれています。

すべての「場所」と「トンネル外」ステータスの間の合計時間を計算する必要があります

現在のテーブル

    ID   ||       time       ||     Status
________________________________________________
      1  ||       08:09:14   ||   Out of Tunnel
      2  ||       08:10:59   ||     Location
      3  ||       08:11:42   ||   Out of Tunnel
      4  ||       08:11:55   ||     Location
      5  ||       08:16:36   ||     Location          
      6  ||       09:41:36   ||     Location
      7  ||       09:43:10   ||   Out of Tunnel
      8  ||       09:43:19   ||     Location

「ロケーション」ステータスは、カウントを開始する必要がある場所を示します。次にステータスが「トンネル外」になったときにカウントを停止する必要があります。対応する「トンネル外」が指定されていない場合は、カウントしないでください。

次に、各合計を合計して総計を計算します。例えば:

  • 開始ID2:08:10:59
  • ID:08:11:42で終了
  • 合計1:00:00:43
  • 開始ID4:08:11:42
  • ID7:09:43:10で終了
  • 合計2:01:31:28
  • 総計:合計1 +合計2 = 01:32:11

望ましい出力

 ______________________
| Total Time in Tunnel |
|______________________|
|                      |
|        01:32:11      |
|______________________|
2
Mrparkin

ID 4で始まる2回目のラウンドのサンプルデータの時間は08:11:55なので、実際にそれが開始点として使用することになっている時間である場合、合計は01:31:58になります。とにかく、LAGおよびLEADウィンドウ関数を使用したソリューションを次に示します。計画でソートを防止する場合は、次のサポートインデックスを作成してください。

create unique index idx_time_status on dbo.t1(time, status);

2016以降で実行している場合は、次のダミーインデックスを作成してバッチ処理を有効にできます。

create nonclustered columnstore index idx_cs on dbo.t1(id) where id = -1 and id = -2;

SQL Server 2019より前では、SQL Serverは、クエリの参加テーブルの少なくとも1つに列ストアインデックスが存在しない場合、バッチ処理の使用を考慮しませんでした。このダミーインデックスを作成すると、それ自体では意味がなくても、ウィンドウ関数に対してより最適なバッチ処理を使用できます。インデックス付きとインデックスなしの両方のプランを確認してください。 詳細はこちら で説明します。

ソリューションコードは次のとおりです。

with c1 as
(
  select *,
    case 
      when status = 'location'
        and lag(status) over(order by time) = 'location' then 'no'
      else 'yes'
    end as keeper
  from dbo.t1
  where status in ('location', 'out of tunnel')
),
c2 as
(
  select *, lead(time) over(order by time) as nxt
  from c1
  where keeper = 'yes'
)
select dateadd(second, sum(datediff(second, time, nxt)), cast('00:00:00' as time(0))) as total
from c2
where status = 'location';

合計時間が24時間未満になると想定して、出力をTIMEとしてフォーマットしました。それ以上の可能性がある場合は、フォーマットロジックを少し追加するだけで済みます。

7
Itzik Ben-Gan
WITH cte AS (
    SELECT t2.time - MIN(t1.time) delta
    FROM test t1
    JOIN test t2 ON t1.time < t2.time 
                AND t2.status = 'Out of Tunnel'
    LEFT JOIN test t3 ON t1.time < t3.time
                     AND t3.time < t2.time
                     AND t3.status = 'Out of Tunnel'
    WHERE t1.status = 'Location'
      AND t3.id IS NULL
    GROUP BY t2.time
)
SELECT SUM(delta) "Total Time in Tunnel"
FROM cte

唯一の欠陥-сonverttimeフィールドは、自分で比較可能で減算可能で合計可能なデータフォーム/タイプ(または適切な場所で適切な関数を使用)に対応しています。

0
Akina