SQL如何在订单集中查找和汇总最大值集

时间:2014-06-02 15:11:19

标签: sql sql-server sql-server-2008

我一直试图找到一种方法来从有序集中选择和求和本地化的最大值。 因此,给出以下有序数据:

HardwareID  Timestamp               Odometer
ABC123      2013-10-28 07:47:20     300
ABC123      2013-09-25 16:40:43     250
ABC123      2013-09-11 16:33:31     200
ABC123      2013-08-08 09:03:52     120
ABC123      2013-08-05 07:52:58     80
ABC123      2013-07-22 07:42:34     30
ABC123      2013-07-03 11:47:55     140
ABC123      2013-06-25 17:27:20     100
ABC123      2013-06-13 12:01:18     50
ABC123      2013-06-11 07:59:50     10

我想要一个查询来拉出并求和两个局部最大值(300 + 140):

HardwareID Odometer
ABC123     440

我已尝试this滑动窗口方法,但无法让它适用于我的方案。是否有一种解决此类问题的常用方法(循环一组并与之前的值进行比较)?

2 个答案:

答案 0 :(得分:0)

SQL Server 2012及更高版本具有lead()lag()功能,对此有很大帮助。

select HardwareId, sum(odometer)
from (select t.*,
             lag(Odometer) over (partition by HardwareId order by TimeStamp) as prevo,
             lead(Odometer) over (partition by HardwareId order by TimeStamp) as nexto
      from table t
     ) t
where Odometer > coalesce(prevo, 0) and Odometer > coalesce(nexto, 0);

你可以这样做是2012年之前的版本,但语法有点麻烦。

答案 1 :(得分:0)

我为您的测试数据添加了一个顺序标识,以使这个示例更容易,但我假设您有一个主键可以利用(如果不是时间戳上的row_number也可以。)

在这个例子中,我只是加入“下一个顺序”行并评估它是否优于。如果是这样,我认为它是一个高峰,并在随后的总和中使用。

希望你可以用它来适应你。

declare @t table (Pk int identity(1,1), HardwareID varchar(10), [Timestamp] datetime, Odometer int);
insert into @t
    select 'ABC123', '2013-10-28 07:47:20', 300 union all
    select 'ABC123', '2013-09-25 16:40:43', 250  union all
    select 'ABC123', '2013-09-11 16:33:31', 200  union all
    select 'ABC123', '2013-08-08 09:03:52', 120  union all
    select 'ABC123', '2013-08-05 07:52:58', 80   union all
    select 'ABC123', '2013-07-22 07:42:34', 30   union all
    select 'ABC123', '2013-07-03 11:47:55', 140  union all
    select 'ABC123', '2013-06-25 17:27:20', 100  union all
    select 'ABC123', '2013-06-13 12:01:18', 50   union all
    select 'ABC123', '2013-06-11 07:59:50', 10;

--to illustrate
select  a.HardwareId,
        a.Odometer,
        [IsAPeak] = case when a.Odometer > isnull(b.Odometer, 0) then 1 else 0 end
from    @t a
left
join    @t b on 
        a.pk = b.pk+1 and
        a.HardwareId = b.HardwareId;

select  a.HardwareId,
        sum(case when a.Odometer > isnull(b.Odometer, 0) then a.Odometer else 0 end)
from    @t a
left
join    @t b on 
        a.pk = b.pk+1 and
        a.HardwareId = b.HardwareId
group
by      a.HardwareId;