The difference between each row value - Sum Error

血红的双手。 提交于 2019-12-12 03:49:09

问题


My main query was solved at the following post

TSQL - Get the difference between each row value

I have one problem of summing the reading values between each row.

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

for the above scenario i am getting the results but when following is the case the readings are coming correct according to the solution provided to me, but i want to increment the difference ...

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

The result of the above readings is as below

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

Those two values in negative should be in positive and the value should be something like 122892 - 122889.

Note : The max value for reading will always be 999999.00 and after that i will again start from 0 upto 999999.00 and again start from 0. This is basically the counting device which counts. Below is the query which was suggested to at stack overflow and i have modified a bit according to my need

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:


What you essentially need is to pretend temporarily that c2.reading didn't wrap around after reaching 1,000,000, and that only when c2.reading < c1.reading. That is, at that point you'd need to increase c2.reading by 1,000,000, then subtract c1.reading. And when c2.reading >= c1.reading, the query should calculate the "normal" difference, i.e. subtract c1.reading from the original (non-increased) c2.reading value.

One way to achieve that logic would be to do something as straightforward as this:

SUM(
  CASE WHEN c2.reading < c1.reading THEN 1000000 ELSE 0 END
  + c2.reading
  - ISNULL(c1.reading, c2.reading)
) AS Count1

However, there's also a different approach.

Your reading values, and, as a consequence, differences between any two of them as well, can never exceed 1,000,000. Therefore, you can freely apply modulo 1,000,000 to a positive difference and that'll give you the same difference back:

d mod 1,000,000 = d

Moreover, adding multiples of 1,000,000 to a positive difference won't affect the result of modulo 1,000,000 because, according to the distributiveness of the modulo operation,

  (d + 1,000,000 * n) mod 1,000,000 =
= d mod 1,000,000 + (1,000,000 * n) mod 1,000,000

The first summand, d mod 1,000,000 results in d, the second one, (1,000,000 * n) mod 1,000,000 yields 0, d + 0 = d.

On the other hand, adding 1,000,000 to a negative difference would give us a correct positive difference.

So, to sum up,

  • adding 1,000,000 to a negative difference gives us a (correct) positive difference,

  • a positive difference modulo 1,000,000 yields the same positive difference, and

  • adding 1,000,000 to a positive difference doesn't affect the result of modulo 1,000,000.

Taking all that into account, we can end up with the following universal expression to calculate a single difference:

(1000000 + c2.reading - ISNULL(c1.reading, c2.reading)) % 1000000

where % is the modulo operator in Transact-SQL.

Put the expression into SUM to get the corresponding aggregated values:

SUM((c2.reading + 1000000 - ISNULL(c1.reading, c2.reading)) % 1000000) AS Count1


来源:https://stackoverflow.com/questions/15064775/the-difference-between-each-row-value-sum-error

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!