问题
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