web-dev-qa-db-ja.com

クエリ結果を複数回分割する

データベースの統計を作成するプロシージャを作成する必要があります。

まず、作業を「簡素化」するために一時テーブルを作成することにしました。

これには、1日の作業単位(NumCavalier)のすべての関連アクション(FormIdNb)が含まれています。

-- 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. 結果を時間間隔で分割する必要があります(1日15分)
  2. 各作業単位「NumCavalier」の「FormIdNb」の最大値を次のように分割する必要があります。

FormIdNb> 3 ==>作業ユニットはその時間間隔でアクティブでした

FormIdNb = 3 ==>作業ユニットはその時間間隔でアイドル状態でした(同じ時間間隔でアクティブでない場合)

FormIdNb <3 ==>作業ユニットはその時間間隔で非アクティブでした(同じ時間間隔でアクティブまたはアイドル状態でない場合)

  1. 最後に、前の値に応じて、作業単位の時間間隔ごとにカウントします。

私はすでにこれを実行しましたが、部分的に機能しますが、前の結合の値は考慮されません(たとえば、作業ユニットが同時にアクティブとアイドルのように見えるなど)。

私はそれを機能させるために多くの変更を加える必要があると思います:

;WITH 
time_cte(StartTime, EndTime) AS
(
SELECT @starttime StartTime, DATEADD(mi, 15, @starttime) EndTime
UNION ALL
SELECT EndTime, DATEADD(mi, 15, EndTime) FROM time_cte
WHERE EndTime < @EndTime
)

SELECT StartTime, Count(DISTINCT CavsTerminal_ACTIVE.NumCavalier),
Count(DISTINCT CavsTerminal_IDLE.NumCavalier), 
Count(DISTINCT CavsTerminal_INACTIVE.NumCavalier)
FROM time_cte
LEFT OUTER JOIN (
SELECT NumCavalier AS NumCavalier, DateHeure
FROM #tmp_DailyMissions
GROUP BY NumCavalier, FormIdNb, DateHeure
HAVING MAX(FormIdNb) > 3
) CavsTerminal_ACTIVE ON  CavsTerminal_ACTIVE.DateHeure BETWEEN time_cte.StartTime AND time_cte.EndTime
LEFT OUTER JOIN (
SELECT NumCavalier AS NumCavalier, DateHeure
FROM #tmp_DailyMissions
GROUP BY NumCavalier, FormIdNb, DateHeure
HAVING MAX(FormIdNb) = 3
) CavsTerminal_IDLE ON  (CavsTerminal_IDLE.DateHeure BETWEEN time_cte.StartTime AND time_cte.EndTime)
LEFT OUTER JOIN (
SELECT NumCavalier AS NumCavalier, DateHeure
FROM #tmp_DailyMissions
GROUP BY NumCavalier, FormIdNb, DateHeure
HAVING MAX(FormIdNb) < 3
) CavsTerminal_INACTIVE ON  (CavsTerminal_INACTIVE.DateHeure BETWEEN time_cte.StartTime AND time_cte.EndTime)
GROUP BY StartTime
2
AlfredLamoule

#2を実装しない場合、クエリはおそらく次のようになります。

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

    UNION ALL

    SELECT
      StartTime = @starttime,
      EndTime   = DATEADD(mi, 15, @starttime)
    FROM
      time_cte
    WHERE
      EndTime < @EndTime
  )
SELECT
  t.StartTime,
  UnitCount = COUNT(d.NumCavalier)
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
;
_

次に、COUNT(d.NumCavalier)FormIdNbの値に基づいて3つの値に分割するために、その値をチェックしますカウント時 –次のように:

_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(CASE WHEN d.FormIdNb < 3 THEN d.NumCavalier END),
  IdleUnitCount     = COUNT(CASE WHEN d.FormIdNb = 3 THEN d.NumCavalier END),
  InactiveUnitCount = COUNT(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
;
_

これは条件付き集計と呼ばれます:ある条件に基づいて結果を集計しています。

このメソッドの魅力の1つは、結果の列セットにCOUNT(d.NumCavalier)を含めることで、必要に応じて同じ出力で合計数を取得できることです。

3
Andriy M