GroupBy关于另一个表上的记录间隔

时间:2016-05-30 08:06:23

标签: sql sql-server

我为我的问题准备了一个sql小提琴。 Here it is这里有一个有效的代码。我在问是否存在一种我没想到的替代解决方案。

CREATE TABLE [Product]
    ([Timestamp] bigint NOT NULL PRIMARY KEY, 
     [Value] float NOT NULL
    )
;

CREATE TABLE [PriceTable]
    ([Timestamp] bigint NOT NULL PRIMARY KEY, 
     [Price] float NOT NULL
    )
;

INSERT INTO [Product]
    ([Timestamp], [Value])
VALUES
    (1, 5),
    (2, 3),
    (4, 9),
    (5, 2),
    (7, 11),
    (9, 3)    
;

INSERT INTO [PriceTable]
    ([Timestamp], [Price])
VALUES
    (1, 1),
    (3, 4),
    (7, 2.5),
    (10, 3)    
;

查询:

SELECT [Totals].*, [PriceTable].[Price] 
FROM 
(
    SELECT [PriceTable].[Timestamp]
           ,SUM([Value]) AS [TotalValue]
    FROM [Product], 
         [PriceTable]
    WHERE [PriceTable].[Timestamp] <= [Product].[Timestamp]
     AND NOT EXISTS (SELECT * FROM [dbo].[PriceTable] pt 
                     WHERE pt.[Timestamp] <= [Product].[Timestamp]
                       AND pt.[Timestamp] > [PriceTable].[Timestamp])
    GROUP BY [PriceTable].[Timestamp]
) AS [Totals]
INNER JOIN [dbo].[PriceTable]
        ON [PriceTable].[Timestamp] = [Totals].[Timestamp]
ORDER BY [PriceTable].[Timestamp]

结果

| Timestamp | TotalValue | Price |
|-----------|------------|-------|
| 1         | 8          | 1     |
| 3         | 11         | 4     |
| 7         | 14         | 2.5   |

这里,我的第一个表[Product]包含不同时间戳的产品值。第二个表[PriceTable]包含不同时间间隔的价格。在设定新价格之前,给定价格有效。因此,带有时间戳1的价格对于时间戳为1和2的产品有效。

我试图获得与给定价格相关的产品总数。小提琴上的SQL产生了我的期望。

是否有更聪明的方法可以获得相同的结果?

顺便说一下,我正在使用SQLServer 2014。

3 个答案:

答案 0 :(得分:1)

DECLARE @Product TABLE
    (
      [Timestamp] BIGINT NOT NULL
                         PRIMARY KEY ,
      [Value] FLOAT NOT NULL
    );

DECLARE @PriceTable TABLE
    (
      [Timestamp] BIGINT NOT NULL
                         PRIMARY KEY ,
      [Price] FLOAT NOT NULL
    );

INSERT  INTO @Product
        ( [Timestamp], [Value] )
VALUES  ( 1, 5 ),
        ( 2, 3 ),
        ( 4, 9 ),
        ( 5, 2 ),
        ( 7, 11 ),
        ( 9, 3 );

INSERT  INTO @PriceTable
        ( [Timestamp], [Price] )
VALUES  ( 1, 1 ),
        ( 3, 4 ),
        ( 7, 2.5 ),
        ( 10, 3 );

WITH    cte
          AS ( SELECT   * ,
                        LEAD(pt.[Timestamp]) OVER ( ORDER BY pt.[Timestamp] ) AS [lTimestamp]
               FROM     @PriceTable pt
             )
    SELECT  cte.[Timestamp] ,
            ( SELECT    SUM(Value)
              FROM      @Product
              WHERE     [Timestamp] >= cte.[Timestamp]
                        AND [Timestamp] < cte.[lTimestamp]
            ) AS [TotalValue],
            cte.[Price]
    FROM    cte

想法是从价格表生成间隔,如:

1 - 3
3 - 7
7 - 10

并总结这些区间中的所有值。

输出:

Timestamp   TotalValue  Price
1           8           1
3           11          4
7           14          2.5
10          NULL        3

如果您想过滤掉没有销售订单的行,您只需添加WHERE子句。

如果你想关闭最后一个间隔,你也可以指出LEAD窗口函数的默认值:

LEAD(pt.[Timestamp], 1, 100) 

我想在制作中会是这样的:

LEAD(pt.[Timestamp], 1, GETDATE()) 

答案 1 :(得分:0)

我认为我的查询更容易阅读。这对你有用吗?

select pt.*, 
(select sum(P.Value) from Product P where 
 P.TimeStamp between pt.TimeStamp and (
 --get the next time stamp
 select min(TimeStamp)-1 from PriceTable where TimeStamp > pt.TimeStamp
 )) as TotalValue from PriceTable pt
 --exclude entries with timestamps greater than those in Product table
 where pt.TimeStamp < (select max(TimeStamp) from Product)

非常详细的问题BTW

答案 2 :(得分:0)

你可以使用cte

;with cte as
(
select  p1.[timestamp] as lowval,
        case
        when    p2.[timestamp] is not null then p2.[timestamp] - 1
        else    999999
        end     hival,
        p1.price
from
(
select  p1.[timestamp],p1.price,
        row_number() over (order by p1.[timestamp]) rn
from    pricetable p1 ) p1
left outer join 
(select p1.[timestamp],p1.price,
        row_number() over (order by p1.[timestamp]) rn
from    pricetable p1) p2 
on      p2.rn = p1.rn + 1
)
select  cte.lowval as 'timestamp',sum(p1.value) TotalValue,cte.price
from    product p1
join    cte on p1.[Timestamp] between cte.lowval and cte.hival
group   by cte.lowval,cte.price
order   by cte.lowval

它更容易理解,执行计划与您的查询(约10%)更便宜相比