9

それで、ここにさらに別の「Xへのクエリを書く」チャレンジがあります。

私は多くのネットワーク化された自動販売機を監視しています。各マシンには、紙幣アクセプター、コインシステム、プリンターなど、いくつかの部品があります。

機械部品の問題はテーブルに記録されます。これを「障害」と呼びましょう。これは次のようになります(無関係なフィールドは省略されています)。

machineid           partid         start_time            end_time
---------           ------         ----------------      ----------------
       1                2          2009-10-05 09:00      NULL
       1                3          2009-10-05 08:00      2009-10-05 10:00
       2                2          2009-09-30 12:00      2009-09-30 14:00
       3                4          2009-09-28 13:00      2009-09-28 15:00
       3                2          2009-09-28 12:00      2009-09-28 14:00

問題が現在進行中の場合、end_dateはNULLです。

マシン全体がダウンしている期間を表示し、重複する範囲を説明して、それらを1つのレコードにまとめることができるクエリが必要です。したがって、上記のサンプルデータの場合、次のようになります。

machineid          start_time            end_time
---------          ----------------      ----------------
       1           2009-10-05 08:00      NULL
       2           2009-09-30 12:00      2009-09-30 14:00
       3           2009-09-28 12:00      2009-09-28 15:00

これを1行ずつ実行する手続き型コードを作成するのは難しいことではありませんが、優れた宣言型SQLクエリの方が便利で、よりエレガントです。それは可能であるはずのようですが、私はそこにたどり着くことができません。

SQL方言はOracleです。それが助けになるなら、分析関数が利用可能です。

ありがとう!

4

8 に答える 8

7

分析を使用すると、データを1回渡すクエリを作成できます(データセットが大きい場合は、これが最も効率的です)。

SELECT machineid, MIN(start_time), MAX(end_time)
  FROM (SELECT machineid, start_time, end_time, 
               SUM(gap) over(PARTITION BY machineid 
                             ORDER BY start_time) contiguous_faults
           FROM (SELECT machineid, start_time, 
                        coalesce(end_time, DATE '9999-12-31') end_time,
                         CASE
                            WHEN start_time > MAX(coalesce(end_time, 
                                                           DATE '9999-12-31'))
                                              over(PARTITION BY machineid 
                                                   ORDER BY start_time 
                                                   ROWS BETWEEN UNBOUNDED PRECEDING
                                                            AND 1 preceding)
                            THEN 1
                         END gap
                    FROM faults))
 GROUP BY machineid, contiguous_faults
 ORDER BY 1, 2

このクエリは、行が以前に開始された行に隣接しているかどうかを判断することから始まります。次に、隣接する行をグループ化します。

于 2009-10-05T22:37:12.043 に答える
2

基本的に、純粋な集合論(たとえば、ループのない有界のクエリ数として)ではそれを行うことはできません(フォレストのカバーパーティションセットを見つける)。

最もセットのような方法でそれを行うには、

  1. フォレストのパーティション分割用の一時テーブルを作成します(10列または11列、障害#1から4、障害#2から4、パーティションID用に1、ノードが挿入されたラウンド用に1、および考えられないさまざまな最適化用に1 38Cの熱で。

  2. ループを実行します(BFSまたはDFS、フォレスト分割アルゴリズムの実装を容易にするために見つけたもの)。グラフと比較して注意が必要なのは、多くのサブツリーを上から現在のサブツリーに結合できることです。

    ループの基本的な構成要素としてsheepsimulatorのクエリを使用できます(たとえば、2つの接続されたノードの検索)

  3. パーティショニングループが完了したら、単に

   min(p1.start_time)、max(p2.end_time)、p1.partition、p2.partitionを選択します
   パーティションp1、パーティションp2から
   ここで、p1.partition = p2.partition
   p1.partition、p2.partitionでグループ化
   

    /*これはCOALESCEを使用して微調整する必要があります
       明白な方法でNULL終了時間を処理するため)* /

フォレスト分割の正確なコードを綴っていないことをお詫びします(ツリー分割の下にファイルされる可能性があります)-私は疲れ果てており、tdataの構造と問題の名前がわかったので、グーグルが1つを生成すると確信しています(またはこれをStackOverflowでより正確に定式化されたQとして投稿します-たとえば、「SQLのループとしてツリーのフォレストを完全に分割するためのアルゴリズムを実装する方法」。

于 2009-10-05T21:40:43.913 に答える
2
SELECT  DISTINCT 
        t1.machineId, 
        MIN(t2.start_time) start_time, 
        MAX(COALESCE(t2.end_time, '3210/01/01')) end_time
FROM FAULTS t1
JOIN FAULTS t2 ON t1.machineId = t2.machineId
                  AND ((t2.start_time >= t1.start_time
                       AND (t1.end_time IS NULL OR t2.start_time <= t1.end_time)
                  )
                  OR
                  (t1.start_time >= t2.start_time 
                       AND (t2.end_time IS NULL OR t1.start_time <= t2.end_time) 
                  ))
GROUP BY t1.machineId, t1.part_id

次のデータでこのクエリをテストしました。

machine_id   |part_id |start_time           |end_time
-------------------------------------------------------------------------
1           |2       |05 Oct 2009 09:00:00  |NULL
1           |3       |05 Oct 2009 08:00:00  |05 Oct 2009 10:00:00
2           |2       |30 Sep 2009 12:00:00  |30 Sep 2009 14:00:00
2           |3       |30 Sep 2009 15:00:00  |30 Sep 2009 16:00:00
2           |4       |30 Sep 2009 16:00:00  |30 Sep 2009 17:00:00
3           |2       |28 Sep 2009 12:00:00  |28 Sep 2009 14:00:00
3           |4       |28 Sep 2009 13:00:00  |28 Sep 2009 15:00:00

私はこれを得た:

machine_id   |start_time             |end_time
-----------------------------------------------------------------
1           |05 Oct 2009 08:00:00   |01 Jan 3210 00:00:00
2           |30 Sep 2009 12:00:00   |30 Sep 2009 14:00:00
2           |30 Sep 2009 15:00:00   |30 Sep 2009 17:00:00
3           |28 Sep 2009 12:00:00   |28 Sep 2009 15:00:00
于 2009-10-05T21:37:53.990 に答える
0

ヘヘ。

区間型をサポートするSIRA_PRISEでは、この問題の解決は次のように簡単です。

SELECT machineID、期間FROM障害。

INここで、「期間」は、開始点と終了点がSQLテーブルのstart_timeとend_timeである時間間隔タイプの属性です。

しかし、おそらくSQLでこれを解決することを余儀なくされており、間隔タイプをサポートしていないシステムでは、私はあなたに多くの勇気を願うだけです。

2つのヒント:

2つの間隔の和集合は、複雑なCASE構造を使用してSQLで処理できます(interval_values_overlapの場合はlowest_start_time、highest_end_time、そのようなものすべて)。

1つにマージされる行の数を事前に知ることができないため、再帰SQLを作成する必要があることに気付くでしょう。

于 2009-10-05T22:27:46.753 に答える
0

これを行うにはストアドプロシージャ、または再帰的な'共通テーブル式(CTE)(SQLサーバーに存在する)のようなものが必要になると思います。そうでない場合(単一のSQLステートメントで)正しい答えを得ることができません。 3つ以上の行が一緒になって、カバーされる日付の連続した範囲を形成する場合。

お気に入り:

 |----------|
           |---------------|
                        |----------------|

実際に演習を行わずに、ストアドプロシージャですべての「候補日付」のテーブルを作成し、既存の行の日付範囲でカバーされていないすべての日付を含むテーブルを作成してから、このセットを「否定」して結果セットを出力します。

于 2009-10-05T21:46:54.427 に答える
0
SELECT machineid, min(start_time), max(ifnull(end_time, '3000-01-01 00:00'))
FROM faults
GROUP BY machineid

ジョブを実行する必要があります(必要に応じて、ifnullを同等のOracle関数に置き換えます)。

于 2009-10-05T21:03:10.363 に答える
0

完全な回答をする時間があればいいのですが、重複するダウンタイムを見つけるためのヒントを次に示します。

select a.machineid, a.start_time, a.end_time, b.start_time, b.end_time
from faults a,
     faults b,
where a.machineid = b.machineid
  and b.start_time >= a.start_time
  and b.start_time <= a.end_time;
于 2009-10-05T21:10:18.460 に答える
0

このディスカッションを参照してください-下部に解決策があります:http ://www.microsoft.com/communities/newsgroups/en-us/default.aspx?dg = microsoft.public.sqlserver.programming&tid = 2bae93da-c70e-4de4-a58b -d8cc0bf8ffd5

于 2009-10-05T22:03:07.167 に答える