SQL Serverで現在の行と次の行の間のdatediffを計算する最良の方法は何ですか?
-
09-06-2019 - |
質問
次の大まかな構造があります。
Object -> Object Revisions -> Data
データは複数のオブジェクト間で共有できます。
私がやろうとしているのは、古いオブジェクトのリビジョンを削除することです。一定期間の最後の変更が保持されるように、最初のアクティブなリビジョンのスプレッドを保持したいと考えています。データは 2 日間で大幅に変更され、その後数か月間放置される可能性があるため、変更が開始される前の最後のリビジョンと新しいセットの最後の変更を保持したいと考えています。
現在、カーソルと一時テーブルを使用して変更間の ID と日付を保持しているので、簡単に解決できる問題を選択して取り除くことができます。これは、@LastID、@LastDate の使用、一時テーブルへの更新と挿入などを意味します。
カーソルと一時テーブルを使用せずに、最初の結果セットの現在の行と次の行の間の日付の差を計算する、より簡単/より良い方法はありますか?
私はSQL Server 2000を使用していますが、これに役立つ2005、2008の新機能にも興味があります。
解決
ID 列が連続している場合は、次のアプローチを使用できます。
SELECT curr.*, DATEDIFF(MINUTE, prev.EventDateTime,curr.EventDateTime) Duration FROM DWLog curr join DWLog prev on prev.EventID = curr.EventID - 1
他のヒント
SQL の例を次に示します。Identity 列がある場合は、「ActivityDate」の代わりにこれを使用できます。
SELECT DATEDIFF(HOUR, prev.ActivityDate, curr.ActivityDate)
FROM MyTable curr
JOIN MyTable prev
ON prev.ObjectID = curr.ObjectID
WHERE prev.ActivityDate =
(SELECT MAX(maxtbl.ActivityDate)
FROM MyTable maxtbl
WHERE maxtbl.ObjectID = curr.ObjectID
AND maxtbl.ActivityDate < curr.ActivityDate)
「prev」を削除することもできますが、削除するには ID が必要であると想定して、そこに残しておきます。
うーん、興味深い挑戦ですね。2005 年以降のピボット機能を使用すれば、自己結合なしでも実行できると思います。
これが私がこれまでに得た情報です。答えを受け入れる前にもう少し時間を置きたいと思いました。
DECLARE @IDs TABLE
(
ID int ,
DateBetween int
)
DECLARE @OID int
SET @OID = 6150
-- Grab the revisions, calc the datediff, and insert into temp table var.
INSERT @IDs
SELECT ID,
DATEDIFF(dd,
(SELECT MAX(ActiveDate)
FROM ObjectRevisionHistory
WHERE ObjectID=@OID AND
ActiveDate < ORH.ActiveDate), ActiveDate)
FROM ObjectRevisionHistory ORH
WHERE ObjectID=@OID
-- Hard set DateBetween for special case revisions to always keep
UPDATE @IDs SET DateBetween = 1000 WHERE ID=(SELECT MIN(ID) FROM @IDs)
UPDATE @IDs SET DateBetween = 1000 WHERE ID=(SELECT MAX(ID) FROM @IDs)
UPDATE @IDs SET DateBetween = 1000
WHERE ID=(SELECT ID
FROM ObjectRevisionHistory
WHERE ObjectID=@OID AND Active=1)
-- Select out IDs for however I need them
SELECT * FROM @IDs
SELECT * FROM @IDs WHERE DateBetween < 2
SELECT * FROM @IDs WHERE DateBetween > 2
これを拡張して、最大限多くのリビジョンを保持し、最初、最後、およびアクティブなリビジョンを維持したまま古いものを削除できるようにしたいと考えています。select top と order by 句を使えば十分簡単なはずですが...そして、ActiveDate を一時テーブルに放り込みます。
Peter の例を機能させましたが、それをサブセレクトに変更しました。両方をいじってみたところ、SQL トレースでは副選択の読み取りが少なくなっていることがわかりました。しかし、それは効果があるので、私の代表が十分に高くなったら、私は彼に投票するつもりです。