0

我的主要问题在以下帖子中得到解决

TSQL - 获取每行值之间的差异

我有一个问题是对每一行之间的读数值求和。

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
4

1 回答 1

1

您本质上需要的是暂时假装c2.reading在达到 1,000,000 后没有回绕,并且仅在c2.reading < c1.reading. 也就是说,此时您需要增加c2.reading1,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。因此,您可以自由地将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

Transact-SQL%中的模运算符在哪里。

将表达式放入SUM得到对应的聚合值:

SUM((c2.reading + 1000000 - ISNULL(c1.reading, c2.reading)) % 1000000) AS Count1
于 2013-02-25T15:31:37.357 回答