具有相同ID的多行之间的SQL差异
Posted
技术标签:
【中文标题】具有相同ID的多行之间的SQL差异【英文标题】:SQL difference between Multiple Rows having the same ID 【发布时间】:2018-10-14 04:12:53 【问题描述】:SQL 服务器 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 会随着时间的推移而永远增加。我想操纵数据以显示随着时间的推移每个 ID 的 VAL 增加了多少。所以时间 2 的值 - 时间 1 的值
理想结果:
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 没有改变时,我得到了很多重复值。
【问题讨论】:
查看 Sql Server 的 LAG() 函数。 什么版本的 SQL Server? sql query for difference between current row and previous row based on datetime的可能重复 【参考方案1】:你可以用这个。
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
【讨论】:
看起来可行。有没有办法将 CTE 插入临时表中我需要做一些额外的过滤? 你可以在选择前写insert into
。喜欢WITH CTE AS ( ... ) INSERT INTO TempTable SELECT ...
@user3055889 什么额外的过滤?插入临时表有点违背 CTE 的主要好处之一?您应该能够根据需要过滤您的 CTE,而无需将其转储到临时表中。
@Shawn 感谢这个想法,刚刚向 CTE 添加了 where 语句,并且能够在那里完成工作。
另外,仅供参考:这绝对是在 SQL LEAD/LAG) 会产生一个平面执行计划,该计划将执行好一点。【参考方案2】:
这应该可以工作:
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
【讨论】:
【参考方案3】:您可以首先在您的#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)
【讨论】:
【参考方案4】:LAG()
在 SQL 2012 中可用。这允许您获取当前行的 val
并从前一行中减去 val
,按 id
分组并按 Time
排序。这将返回前两行的NULL
,因为它们没有以前的记录可供比较。您可以通过将查询放在子选择中然后应用WHERE valDiff IS NULL
来排除它们,或者您可以使用LAG()
> LAG(Val,1,0)
的第三个参数默认valDiff
将前两行默认为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
Results:
| 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 |
【讨论】:
【参考方案5】:如果你有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 以及一些空值。 @user3055889 适用于我的示例数据。看这个演示rextester.com/FGKB7753以上是关于具有相同ID的多行之间的SQL差异的主要内容,如果未能解决你的问题,请参考以下文章