0

SQL SERVER 2008 を使用して、特定の間隔でチェックポイントがカウントされるたびに行を返す関数を作成しようとしています。
言い換えれば、特定のオブジェクトが特定の間隔でアクティブだったことを示すテーブルが与えられた場合

[ID]   [TIME FROM]      [TIME TO]
23     12:34:00         13:14:00

結果セットとして、次のようなテーブルを取得しようとしていました。

[ID]   [TimeCheck]      [flag]
23     12:00:00        0  
23     12:15:00        0  
23     12:30:00        1  
23     12:45:00        1  
23     13:00:00        1  
23     13:15:00        0     

これを使用して、各 ID の間隔を提供するテーブルにリンクできます (下のfinalgoalを参照)
。その理由は、統計を計算してグラフを作成し、チェックした ID の数を数えたいからです。特定のチェックポイント時間のセットで。
カーソルを使用することもできましたが、それは非常に大まかなアプローチに聞こえるので、誰かがより良いものを提案してくれることを願っていました.
これは理想的な再帰問題に聞こえるので、CTEまたは再帰関数を考えていましたが、解決できませんでした

ご提案いただきありがとうございます。---- 編集 --- もちろん、次のような関数を使用できます。

CREATE FUNCTION test_GetTimePoints (@ID INT, @timeFrom TIME, @timeTo TIME ,@intervalMinutes INT)
RETURNS @result TABLE ( [ID] INT , LasTimeCheck TIME , flag BIT)
AS
BEGIN
DECLARE @curTick INT = DATEDIFF(MINUTE,'00:00:00',@timeFrom)/@intervalMinutes+1
DECLARE @endTick INT = DATEDIFF(MINUTE,'00:00:00',@timeTo)/@intervalMinutes
WHILE ( @curTick < = @endTick )
BEGIN
  INSERT INTO @result
  SELECT @ID, DATEADD(MINUTE,@curTick*@intervalMinutes,0),1
  SET @curTick = @curTick + 1
END
RETURN
END



最終的な目標は、次のようなことです。

select ID,TS_In,TS_end, A.* FROM VEH M LEFT OUTER JOIN (SELECT * FROM 
dbo.test_GetTimePoints(ID,M.ts_In,M.ts_end,15) )A ON A.ID=M.ID

ID,M.ts_In,M.ts_end,15関数にパラメーターとして与えることができないため、明らかに機能していません。
同じ結果を達成するためのアイデアはありますか?

4

2 に答える 2

0

すでに関数がある場合、最も簡単な方法はOUTER APPLYを使用することです:

SELECT ID,TS_In,TS_end, A.* 
  FROM VEH M 
 OUTER APPLY
 (
   SELECT * 
     FROM dbo.test_GetTimePoints(ID, M.ts_In, M.ts_end, 15) A
 ) A

しかし、この関数は、オブジェクトのアクティビティの間隔外の時間を考慮していないため、疑わしいように見えます。ある間隔 (1 日?) だけの時間のリストを生成するように変更し、VEH とクロス結合して、15 分の期間の開始と終了の間の時間をマークすることができます。

SELECT ID, TS_In, TS_end, 
       CASE WHEN M.TS_In <= dateadd (minute, 15, A.LastTimeCheck )
             AND M.TS_end >= A.LastTimeCheck
            THEN 1
            ELSE 0
        END Flag
  FROM VEH M 
 CROSS JOIN dbo.test_GetTimePoints('07:00:00', '23:00:00', 15) A

関数をすべて削除するには、再帰 CTE を使用してタイム テーブルを生成します。

; WITH test_GetTimePoints (LastTimeCheck) AS
(
    SELECT CAST('07:00:00' as time)
    UNION ALL
    SELECT dateadd(minute, 15, LastTimeCheck)
      FROM test_GetTimePoints
       WHERE LastTimeCheck < CAST ('23:00:00' as time)
)
SELECT ID, TS_In, TS_end, 
       CASE WHEN M.TS_In <= dateadd (minute, 15, A.LastTimeCheck )
             AND M.TS_end >= A.LastTimeCheck
            THEN 1
            ELSE 0
        END Flag
  FROM VEH M 
 CROSS JOIN test_GetTimePoints A

アップデート:

このクエリは他のクエリと同様です。アプリケーションからパラメータを送信できます。つまり、@interval intうまく機能します。CTE バリアントを引き続き使用できますが、不要な時間を除外する必要があります。

; WITH test_GetTimePoints (LastTimeCheck) AS
(
    SELECT CAST('00:00:00' as time)
    UNION ALL
    SELECT dateadd(minute, @interval, LastTimeCheck)
      FROM test_GetTimePoints
       WHERE LastTimeCheck < dateadd (minute, - @interval, 
                                      CAST ('00:00:00' as time))
)
SELECT ID, TS_In, TS_end
  FROM VEH M 
 CROSS JOIN test_GetTimePoints A
 WHERE M.TS_In <= dateadd (minute, @interval, A.LastTimeCheck )
   AND M.TS_end >= A.LastTimeCheck
-- Default = 100, but we need to produce up to 1440 records
-- So we turn the limit off with zero.
OPTION (maxrecursion 0)

より良い解決策は、カレンダー テーブル (この場合は 1 日のすべての分) を用意し、CROSS APPLY を使用することです。

SELECT ID,TS_In,TS_end, A.LastTimeCheck 
  FROM VEH M 
 OUTER APPLY
 (
   SELECT LastTimeCheck 
     FROM TimeTable A
    WHERE (datediff (minute, 0, LastTimeCheck) % @interval = 0)
      AND M.TS_In <= dateadd (minute, @interval, A.LastTimeCheck )
      AND M.TS_end >= A.LastTimeCheck
 ) A

TimeTable は、@interval を 1 に設定して上記の CTE を使用して入力できます。

于 2012-05-05T18:34:19.177 に答える