我的主要查询已在以下文章中解决
TSQL - Get the difference between each row value
我有一个问题就是每行之间的读数值相加。
id device_id time reading shift_id
150323 3 2013-02-25 15:22:01.273 999948.00 43
150324 1 2013-02-25 15:22:01.423 999962.00 43
150325 3 2013-02-25 15:22:01.463 999966.00 43
150326 1 2013-02-25 15:22:01.610 999979.00 43
150327 3 2013-02-25 15:22:01.650 999983.00 43
150328 1 2013-02-25 15:22:01.810 999997.00 43
对于上面的场景我得到的结果但是在下面的情况下,根据提供给我的解决方案,读数是正确的,但我想增加差异......
id device_id time reading shift_id
150322 1 2013-02-25 15:22:01.233 999945.00 43
150323 3 2013-02-25 15:22:01.273 999948.00 43
150324 1 2013-02-25 15:22:01.423 999962.00 43
150325 3 2013-02-25 15:22:01.463 999966.00 43
150326 1 2013-02-25 15:22:01.610 999979.00 43
150327 3 2013-02-25 15:22:01.650 999983.00 43
150328 1 2013-02-25 15:22:01.810 999997.00 43
150329 3 2013-02-25 15:22:01.853 1.00 43
150330 1 2013-02-25 15:22:02.000 15.00 43
150331 3 2013-02-25 15:22:02.040 18.00 43
150332 1 2013-02-25 15:22:02.187 32.00 43
以上读数的结果如下
Day Shifts Hour Device ID Count1
2013-02-25 2nd 11 1 39145.00
2013-02-25 2nd 11 3 39148.00
2013-02-25 2nd 12 1 248022.00
2013-02-25 2nd 12 3 248022.00
2013-02-25 2nd 13 1 389195.00
2013-02-25 2nd 13 3 389197.00
2013-02-25 2nd 14 1 201855.00
2013-02-25 2nd 14 3 201854.00
2013-02-25 2nd 15 1 -877108.00
2013-02-25 2nd 15 3 -877112.00
负面的这两个值应该是正值,值应该是这样的 122892 - 122889.
注意:读数的最大值将始终为999999.00,然后我将再次从0开始到999999.00并再次从0开始。这基本上是计数的计数设备。下面是在堆栈溢出时建议的查询,我根据需要修改了一下
declare @fromdate datetime;
declare @todate datetime;
declare @total as decimal(18,2);
SET @fromdate = '2/23/2013 10:51:17 AM';
SET @todate ='2/25/2013 12:10:56 PM';
WITH cte AS
(
SELECT *,
ROW_NUMBER() OVER(PARTITION BY device_id ORDER BY [time]) AS NId
FROM [dbo].[readings] r
where cast(r.time as date)>= CAST(@fromdate as date) and
cast(r.time as date) <= CAST(@todate as date) and
r.device_id<>5
)
SELECT CAST (c1.[time] as DATE) as [Day],
(
select s.name from shifts s where s.id = c1.shift_id
) as Shifts,
DATEPART(hour,c1.time) as [Hour],
c1.device_id as [Device ID],
(select
case when sum(c2.reading - ISNULL(c1.reading, c2.reading)) < 0 then
sum(c1.reading - ISNULL(c2.reading, c1.reading))
else
sum(c2.reading - ISNULL(c1.reading, c2.reading))
end
) AS Count1
FROM cte c1 left JOIN cte c2 ON c1.device_id = c2.device_id AND
c1.NId + 1 = c2.NId
group by cast(c1.time as DATE), c1.shift_id , DATEPART(hour,c1.time), c1.device_id
order by cast(c1.time as DATE), c1.shift_id,DATEPART(hour,c1.time), c1.device_id
答案 0 :(得分:1)
你真正需要的是暂时假装c2.reading
在达到1,000,000后没有环绕,而且仅在c2.reading < c1.reading
时。也就是说,此时您需要将c2.reading
增加1,000,000,然后减去c1.reading
。当c2.reading >= c1.reading
时,查询应计算“正常”差异,即从原始(非增加)c1.reading
值中减去c2.reading
。
实现这种逻辑的一种方法是做一些像这样简单的事情:
SUM(
CASE WHEN c2.reading < c1.reading THEN 1000000 ELSE 0 END
+ c2.reading
- ISNULL(c1.reading, c2.reading)
) AS Count1
然而,还有一种不同的方法。
您的阅读价值,以及其中任何两个之间的差异,也不会超过1,000,000。因此,您可以自由地将modulo 1,000,000应用于正面差异,并且会给您带来相同的差异:
d mod 1,000,000 = d
此外,将1,000,000的倍数加到正差值不会影响模数1,000,000的结果,因为根据模运算的分布,
(d + 1,000,000 * n) mod 1,000,000 =
= d mod 1,000,000 + (1,000,000 * n) mod 1,000,000
第一个加数,d mod 1,000,000
得到d
,第二个加号(1,000,000 * n) mod 1,000,000
产生0,d + 0 = d
。
另一方面,为负差异添加1,000,000会给我们带来正确的正面差异。
所以,总结一下,
在负差异中加入1,000,000给我们一个(正确的)正差异,
以1,000,000为单位的正差异产生相同的正差异,
将1,000,000添加到正差异不会影响模数1,000,000的结果。
考虑到所有这些因素,我们可以得到以下通用表达式来计算单个差异:
(1000000 + c2.reading - ISNULL(c1.reading, c2.reading)) % 1000000
其中%
是模运算符in Transact-SQL。
将表达式放入SUM
以获取相应的聚合值:
SUM((c2.reading + 1000000 - ISNULL(c1.reading, c2.reading)) % 1000000) AS Count1