每个行值之间的差异 - Sum Error

时间:2013-02-25 10:24:28

标签: sql-server-2008 tsql group-by sum

我的主要查询已在以下文章中解决

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

1 个答案:

答案 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