Подтвердить что ты не робот

Выберите строки, в которых значение столбца изменилось

Скажем, у меня есть следующая таблица:

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/, но мой запрос не завершился через час! Я думаю, что соединения взорвут размер строки на что-то неуправляемое (или я напортачил).

Я могу решить эту проблему с помощью кода С# и нескольких вызовов db, но это похоже на то, что можно было бы сделать в функции с табличной оценкой или SP, которая была бы намного приятнее.

Кроме того, решение, которое работает только с увеличением Value, в порядке, если это проще.

4b9b3361

Ответ 1

Я думаю, что это то, что вам нужно:

;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;

Это может быть медленным, если набор результатов большой, и нет хорошего индекса поддержки...

ИЗМЕНИТЬ

Ах, подождите секунду, значения идут вверх и вниз, а не только вверх... Если это так, вы можете попробовать этот гораздо более медленный подход:

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

Ответ 2

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

Ответ 3

Мы можем сделать это, используя подзапросы также

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.

Ответ 4

Интересно - но у меня есть вариант, который я не думаю, что приведенный выше код будет обрабатывать. Я полагаю, что могу описать аналогичную ситуацию без необходимости создавать слишком сложный набор данных - он похож на банковский счет и имеет несколько столбцов, повторяющихся каждый день - я хочу видеть только дни, в которые изменяются детали >>> Date Balance Product набор Регион Кредит Штат Кампейн 01/03/2019 £ 200,00 Cycles East Good Normal - * 02.03.2009 £ 200.00 Cycles East Good Normal
03/03/2019 £ 200,00 Cycles East Good Нормальный
03/03/2019 £ 550,00 Cycles South Good Normal - * 05/03/2019 £ 550,00 Cycles South Good Normal
03/06/2019 £ 550,00 Cycles South Good Spring - * 07/03/2019 £ 550,00 Cycles South Good Spring
08/03/2019 £ 550,00 Грузовики Южная Бедная Spring - * 03.09.2009 £ 550,00 Грузовики Южная Бедная Spring
10/03/2019 £ 820,00 Грузовики South Poor Spring - * 11.03.2009 £ 820,00 Грузовики North Poor Spring - * 12/03/2019 £ 820,00 Trucks North Poor Spring
13/03/2019 £ 820,00 Самолеты на Северную Плохую Пасху - * 14/03/2019 £ 820,00 Самолеты на Северную Плохую Пасху
15/03/2019 £ 820,00 Самолеты Северная Плохая Пасха
16/03/2019 £ 820,00 Самолеты Север OK Пасха - *

Кто-нибудь заинтересован в движении? - Большое спасибо!