Разница SQL между несколькими строками, имеющими одинаковый идентификатор - PullRequest
0 голосов
/ 03 мая 2018

SQL Sever 2012

Необработанные данные

ID   VAL   Time
+---+----+---------------------+
| 2 |  1 | 2015-05-09 12:54:39 |
| 3 | 10 | 2015-05-09 12:54:39 |
| 2 |  1 | 2015-05-09 12:56:39 |
| 3 | 10 | 2015-05-09 12:56:39 |
| 2 |  5 | 2015-05-09 13:48:30 |
| 3 | 16 | 2015-05-09 13:48:30 |
| 2 |  7 | 2015-05-09 15:01:09 |
| 3 | 20 | 2015-05-09 15:01:09 |
+---+----+---------------------+ 

У меня есть таблица, где VAL постоянно увеличивается во времени. Я хочу манипулировать данными, чтобы показать, насколько VAL увеличивается для каждого идентификатора с течением времени. So Val в Time2 - Val в Time1

Идеальный результат:

ID   VALI   Time
+---+----+---------------------+
| 2 |  0 | 2015-05-09 12:56:39 |
| 3 |  0 | 2015-05-09 12:56:39 |
| 2 |  4 | 2015-05-09 13:48:30 |
| 3 |  6 | 2015-05-09 13:48:30 |
| 2 |  2 | 2015-05-09 15:01:09 |
| 3 |  4 | 2015-05-09 15:01:09 |
+---+----+---------------------+ 

Код до сих пор:

select
t1.Time,t1.[ID],t2.[VAL]-t1.[VAL] AS [ValI]
from #tempTable t1
inner join #tempTable t2 ON t1.[ID]=t2.[ID]
AND t1.[Time]<t2.[Time]

Мне нужно вычислить разницу между текущей меткой времени и ТОЛЬКО временем прямо перед текущей меткой, а не всеми метками времени до текущей метки времени. На данный момент я получаю много повторяющихся значений, когда VAL не изменился.

Ответы [ 5 ]

0 голосов
/ 03 мая 2018

LAG() стал доступен в SQL 2012. Это позволяет вам взять текущую строку val и вычесть val из предыдущей строки, сгруппированные по id и отсортированные по Time. Это вернет NULL для первых двух строк, так как у них нет предыдущей записи для сравнения. Вы можете исключить их, поместив запрос в подвыбор, затем применив WHERE valDiff IS NULL, или вы можете по умолчанию valDiff, используя третий аргумент LAG()> LAG(Val,1,0), по умолчанию первые две строки равны 0 .

SQL Fiddle

Настройка схемы MS SQL Server 2017 :

CREATE TABLE t1 ( ID int, VAL int, [Time] datetime) ;

INSERT INTO t1 ( ID, Val, [Time] )
VALUES 
    ( 2, 1 , '2015-05-09 12:54:39')
  , ( 3, 10, '2015-05-09 12:54:39')
  , ( 2, 1 , '2015-05-09 12:56:39')
  , ( 3, 10, '2015-05-09 12:56:39')
  , ( 2, 5 , '2015-05-09 13:48:30')
  , ( 3, 16, '2015-05-09 13:48:30')
  , ( 2, 7 , '2015-05-09 15:01:09')
  , ( 3, 20, '2015-05-09 15:01:09')
;

Запрос 1 :

SELECT s1.ID
  , s1.ValDiff
  , FORMAT(s1.[Time], 'yyyy-MM-dd hh:mm:ss') AS fTime
FROM (
  SELECT ID
    , Val - LAG(Val,1) OVER ( PARTITION BY ID ORDER BY [Time],ID ) AS ValDiff
    , [Time]
  FROM t1
) s1
WHERE s1.valDiff IS NOT NULL
ORDER BY s1.[Time],s1.ID

Результаты

| ID |    ValI |               fTime |
|----|---------|---------------------|
|  2 |       0 | 2015-05-09 12:56:39 |
|  3 |       0 | 2015-05-09 12:56:39 |
|  2 |       4 | 2015-05-09 01:48:30 |
|  3 |       6 | 2015-05-09 01:48:30 |
|  2 |       2 | 2015-05-09 03:01:09 |
|  3 |       4 | 2015-05-09 03:01:09 |
0 голосов
/ 03 мая 2018

Вы можете использовать это.

DECLARE @MyTable TABLE (ID INT,   VAL INT,  [Time] DATETIME)
INSERT INTO @MyTable VALUES
(2,  1 ,'2015-05-09 12:54:39'),
(3, 10 ,'2015-05-09 12:54:39'),
(2,  1 ,'2015-05-09 12:56:39'),
(3, 10 ,'2015-05-09 12:56:39'),
(2,  5 ,'2015-05-09 13:48:30'),
(3, 16 ,'2015-05-09 13:48:30'),
(2,  7 ,'2015-05-09 15:01:09'),
(3, 20 ,'2015-05-09 15:01:09')


;WITH CTE AS (
    SELECT *, ROW_NUMBER() OVER(PARTITION BY ID ORDER BY [Time]) RN FROM @MyTable
)
SELECT T1.ID, T2.VAL - T1.VAL AS VALI, T2.Time FROM CTE T1
    INNER JOIN CTE T2 ON T1.ID = T2.ID AND T1.RN = T2.RN - 1
ORDER BY T1.[Time], T1.ID

Результат:

ID          VALI        Time
----------- ----------- -----------------------
2           0           2015-05-09 12:56:39.000
3           0           2015-05-09 12:56:39.000
2           4           2015-05-09 13:48:30.000
3           6           2015-05-09 13:48:30.000
2           2           2015-05-09 15:01:09.000
3           4           2015-05-09 15:01:09.000
0 голосов
/ 03 мая 2018

Вот это должно работать:

 select id, time, val-prevval val1 from (
 select * , lag(val, 1, 0) over(partition by  id order by val, time) prevVal from #Temp)A
 order by time
0 голосов
/ 03 мая 2018

Если у вас есть LAG

DEMO

   SELECT
        id
      , val - LAG(val, 1) OVER (PARTITION BY id ORDER BY time ASC) AS VALI
      , time
    FROM #TempTable
    ORDER BY time ASC, ID ASC
0 голосов
/ 03 мая 2018

Вы можете сначала поставить ранг на #tempTable, упорядоченный по убыванию времени и разделенный по ID.

Тогда ваше объединение становится таким:

select
    t1.Time,
    t1.[ID],
    t1.[VAL] - t2.[VAL] AS [ValI]
from #tempTable t1
inner join #tempTable t2 ON t1.[ID] = t2.[ID]
    AND t2.Rank = (t1.Rank + 1)
...