次の表があるとします。
Value Time
0 15/06/2012 8:03:43 PM
1 15/06/2012 8:03:43 PM *
1 15/06/2012 8:03:48 PM
1 15/06/2012 8:03:53 PM
1 15/06/2012 8:03:58 PM
2 15/06/2012 8:04:03 PM *
2 15/06/2012 8:04:08 PM
3 15/06/2012 8:04:13 PM *
3 15/06/2012 8:04:18 PM
3 15/06/2012 8:04:23 PM
2 15/06/2012 8:04:28 PM *
2 15/06/2012 8:04:33 PM
スター付きの行、つまりValue
が変更された行を選択するにはどうすればよいですか?基本的に、Value
が変更された時間を見つけようとしているため、それらの時間間隔に基づいて他のクエリを実行できます。解決策は、事前にValue
またはTime
を知っていることに依存すべきではありません。
これはそれほど難しいことではないように思えます(しかし、明らかに私にとっては十分に難しいです!)。
現在、SQL Server 2008を使用していますが、新しいウィンドウ/分析関数が役立つ場合は2012にアクセスできます。
ここでソリューションを適応させてみました http://blog.sqlauthority.com/2011/11/24/sql-server-solution-to-puzzle-simulate-lead-and-lag-without-using-sql- server-2012-analytic-function / しかし、クエリは1時間後に完了しませんでした!結合により、行サイズが管理不能なサイズに爆発する(または、それを台無しにした)と思います。
この問題はC#コードと複数のdb呼び出しで解決できますが、テーブル値関数またはSPの方がはるかに優れています。
また、増加するValue
でのみ機能するソリューションは、それが簡単であればOKです。
私はこれがあなたが求めていることだと思う:
;WITH x AS
(
SELECT value, time, rn = ROW_NUMBER() OVER
(PARTITION BY Value ORDER BY Time)
FROM dbo.table
)
SELECT * FROM x WHERE rn = 1;
結果セットが大きく、適切なサポートインデックスがない場合、これは遅い可能性があります...
[〜#〜] edit [〜#〜]
ああ、ちょっと待ってください、値が上下するだけでなく、上下します...もしそうなら、このずっと遅いアプローチを試すことができます:
DECLARE @x TABLE(value INT, [time] DATETIME)
INSERT @x VALUES
(0,'20120615 8:03:43 PM'),--
(1,'20120615 8:03:43 PM'),--*
(1,'20120615 8:03:48 PM'),--
(1,'20120615 8:03:53 PM'),--
(1,'20120615 8:03:58 PM'),--
(2,'20120615 8:04:03 PM'),--*
(2,'20120615 8:04:08 PM'),--
(3,'20120615 8:04:13 PM'),--*
(3,'20120615 8:04:18 PM'),--
(3,'20120615 8:04:23 PM'),--
(2,'20120615 8:04:28 PM'),--*
(2,'20120615 8:04:33 PM');
;WITH x AS
(
SELECT *, rn = ROW_NUMBER() OVER (ORDER BY time)
FROM @x
)
SELECT x.value, x.[time]
FROM x LEFT OUTER JOIN x AS y
ON x.rn = y.rn + 1
AND x.value <> y.value
WHERE y.value IS NOT NULL;
結果:
value time
----- -----------------------
1 2012-06-15 20:03:43.000
2 2012-06-15 20:04:03.000
3 2012-06-15 20:04:13.000
2 2012-06-15 20:04:28.000
DECLARE @x TABLE(value INT, [time] DATETIME)
INSERT @x VALUES
(0,'20120615 8:03:43 PM'),--
(1,'20120615 8:03:43 PM'),--*
(1,'20120615 8:03:48 PM'),--
(1,'20120615 8:03:53 PM'),--
(1,'20120615 8:03:58 PM'),--
(2,'20120615 8:04:03 PM'),--*
(2,'20120615 8:04:08 PM'),--
(3,'20120615 8:04:13 PM'),--*
(3,'20120615 8:04:18 PM'),--
(3,'20120615 8:04:23 PM'),--
(2,'20120615 8:04:28 PM'),--*
(2,'20120615 8:04:33 PM');
; with temp as
(
SELECT
value, [time], lag(value,1,-1) over (order by [time] ) as lastValue
FROM @x
)
SELECT
[value],[time]
FROM
temp
WHERE value <> lastValue
結果:
value time
---------------------------
0 2012-06-15 20:03:43.000
1 2012-06-15 20:03:43.000
2 2012-06-15 20:04:03.000
3 2012-06-15 20:04:13.000
2 2012-06-15 20:04:28.000
サブクエリを使用してこれを行うこともできます
SELECT sub1.value, sub1.time FROM
(SELECT *,rn,id FROM
(SELECT *,row_number() over (partition by value order by time) AS rn, row_number() over (order by time) AS id FROM x ) order by time) sub1
LEFT OUTER JOIN
(SELECT *,rn,id FROM
(SELECT *,row_number() over (partition by value order by time) AS rn, row_number() over (order by time) AS id FROM x ) order by time) sub2
ON sub1.id = sub2.id + 1
WHERE sub1.rn - sub2.rn <> 1 OR sub2.rn IS NULL;
したがって、2行の値を変更して比較すると、rnの差は1と等しくなりません。そうでない場合、rn値は1ずつ増加するので、次の行のrn値との差が1ではないすべての行を選択し、 sub2.rn IS NULLは、結合がid = 2から発生するため、最初の行に使用されます。