web-dev-qa-db-ja.com

個別のカウントから結果をフィルタリングする

データベースにstatisticsを作成するようにプロシージャを変更する必要があります。

これらの統計を作成するために必要なすべてのデータを含む一時テーブルを取得しました。
関連するすべてのアクションが含まれていますFormIdNb作業単位NumCavalier 1日で:

-- Every action from all units will be stored in this temp table
-- DateHeure = Time of action
-- NumCavalier = ID of working unit
-- FormIdNb = Action type
CREATE TABLE #tmp_DailyMissions (
DateHeure datetime,
NumCavalier  nchar(3),
FormIdNb int
)

INSERT INTO #tmp_DailyMissions
SELECT        DateHeure, Cavalier.NumCavalier, FormIdNb
FROM            ECN4, Cavalier
WHERE        (DateHeure BETWEEN @StartTime AND @EndTime) AND (Cavalier.Terminal = @terminal) AND (Cavalier.NumCavalier = ECN4.NumCavalier)

この一時テーブルには、すべての作業ユニットが1日で行ったすべてのアクションが格納されます(ロギングシステムと同様)。
FormIdNbの重要な値は次のとおりです。

FormIdNb> 3 ==>作業ユニットはアクティブでした
FormIdNb = 3 ==>作業ユニットはアイドル状態でした
FormIdNb <3 ==>作業ユニットは非アクティブでした

私が今受け取ったリクエスト(@AndriyMのおかげで)は、[〜#〜] active [〜#〜][〜#〜]であった作業ユニットの数を返しますアイドル[〜#〜]および[〜#〜]非アクティブ[〜#〜] 1日の各時間間隔(15分):

WITH time_cte(StartTime, EndTime) AS
  (
    SELECT
      StartTime = @starttime,
      EndTime   = DATEADD(mi, 15, @starttime)

    UNION ALL

    SELECT
      EndTime,
      DATEADD(mi, 15, EndTime)
    FROM
      time_cte
    WHERE
      EndTime < @EndTime
  )
SELECT
  t.StartTime,
  ActiveUnitCount   = COUNT(DISTINCT(CASE WHEN d.FormIdNb > 3 THEN d.NumCavalier END)),
  IdleUnitCount     = COUNT(DISTINCT(CASE WHEN d.FormIdNb = 3 THEN d.NumCavalier END)),
  InactiveUnitCount = COUNT(DISTINCT(CASE WHEN d.FormIdNb < 3 THEN d.NumCavalier END))
FROM
  time_cte AS t
  LEFT OUTER JOIN #tmp_DailyMissions AS d
    ON d.DateHeure >= t.StartTime
    AND d.DateHeure < t.EndTime
GROUP BY
  t.StartTime
;

問題は、上で述べたように、私が使用する一時テーブルがデータをロギングシステムとして格納することです。
これは、同じ時間間隔の作業ユニットに対して、任意の値 of FormIdNbを含めることができることを意味します。
例:1行FormIdNb = 2、1行FormIdNb = 3および1行FormIdNb = 4。

私の質問は:
無関係な値を取り除くリクエストを行う方法は?

より正確には:
作業ユニットが[〜#〜] active [〜#〜]であったが、[〜#〜] idle [〜#〜]でもあった場合および/または[〜#〜]非アクティブ[〜#〜]一定の間隔で、この作業ユニットを[〜#〜]アイドル[〜#]から「削除」する方法〜]および[〜#〜]非アクティブ[〜#〜]カウントし、時間間隔ごとにFormIdNbの最大値のみを保持しますか?

1
AlfredLamoule

Scott Hodginに同意します。基本的に、FormIdNbではなくMAX(FormIdNb)を検討し、MAXの結果がより大きいか、等しいか、または等しいかに基づいて結果をカウントします。 3未満。

スコットが示唆しているように、相関サブクエリを結合条件に追加することは1つの方法です。

もう1つは、派生テーブルを使用して、最初に最大FormIdNb per NumCavalierおよび範囲を取得することです。

SELECT
  t.StartTime,
  d.NumCavalier,
  MaxFormIdNb = MAX(d.FormIdNb)
FROM
  time_cte AS t
  LEFT OUTER JOIN #tmp_DailyMissions AS d
    ON d.DateHeure >= t.StartTime
    AND d.DateHeure < t.EndTime
GROUP BY
  t.StartTime,
  d.NumCavalier

そして、その時だけカウントを取得します。これはクエリ全体です:

WITH time_cte(StartTime, EndTime) AS
  (
    SELECT
      StartTime = @starttime,
      EndTime   = DATEADD(mi, 15, @starttime)

    UNION ALL

    SELECT
      EndTime,
      DATEADD(mi, 15, EndTime)
    FROM
      time_cte
    WHERE
      EndTime < @EndTime
  )
SELECT
  StartTime,
  ActiveUnitCount   = COUNT(CASE WHEN MaxFormIdNb > 3 THEN d.NumCavalier END),
  IdleUnitCount     = COUNT(CASE WHEN MaxFormIdNb = 3 THEN d.NumCavalier END),
  InactiveUnitCount = COUNT(CASE WHEN MaxFormIdNb < 3 THEN d.NumCavalier END)
FROM
  (
    SELECT
      t.StartTime,
      d.NumCavalier,
      MaxFormIdNb = MAX(d.FormIdNb)
    FROM
      time_cte AS t
      LEFT OUTER JOIN #tmp_DailyMissions AS d
        ON d.DateHeure >= t.StartTime
        AND d.DateHeure < t.EndTime
    GROUP BY
      t.StartTime,
      d.NumCavalier
  ) AS s
GROUP BY
  t.StartTime
;

派生テーブルは個別のNumCavalierのみを生成するため、現在はCOUNT(...)であり、COUNT(DISTINCT ...)ではないことに注意してください。 =とにかく値。

1
Andriy M

おそらく、何かが足りないのですが、処理しているタイムスライスの各NumCavalierにmax(formidnb)が必要なようです。私はこれを完全に構文チェックしていませんが、セミコロンのすぐ上に以下を追加できると思います

AND d.FormIdNb = 
(
select MAX(FormIdNb) 
FROM #tmp_DailyMissions
WHERE NumCavalier = d.NumCavalier and
DateHeure >= t.StartTime
AND DateHeure < t.EndTime
)
2
Scott Hodgin