2013-02-25 21 views
0

我的主查询在以下后每一行价值之间的差额 - 和错误

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

你什么本质上需要的是暂时假装c2.reading没有环绕达到百万之后,那只有当时c2.reading < c1.reading。也就是说,那时你需要增加c2.reading 1,000,000,然后减去c1.reading。并且当c2.reading >= c1.reading时,查询应计算“正常”差异,即从原始(未增加的)c2.reading值中减去c1.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 

此外,增加100万的倍数,以产生积极的影响,不会影响模1,000,000的结果,因为,根据取模运算的distributiveness,

(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,​​。

另一方面,增加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 
+0

嘿安德烈,你的魔法工作。谢谢您的帮助。 – 2013-02-26 01:58:18

相关问题