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

Sql 关于在另一个表上记录间隔的GroupBy,sql,sql-server,Sql,Sql Server,我为我的问题准备了一把sql小提琴。这里有一个工作代码。我想问的是,是否存在我认为不存在的替代解决办法 CREATE TABLE [Product] ([Timestamp] bigint NOT NULL PRIMARY KEY, [Value] float NOT NULL ) ; CREATE TABLE [PriceTable] ([Timestamp] bigint NOT NULL PRIMARY KEY, [Price] float

我为我的问题准备了一把sql小提琴。这里有一个工作代码。我想问的是,是否存在我认为不存在的替代解决办法

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]
这里,我的第一个表[Product]包含不同时间戳的产品值。第二个表[价格表]包含不同时间间隔的价格。给定的价格在设置新价格之前有效。因此,时间戳为1的价格对时间戳为1和2的产品有效

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

有没有更聪明的方法可以得到同样的结果


顺便说一句,我正在使用SQLServer2014。

我想我有一个更容易阅读的查询。这对你有用吗

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)
非常详细的问题顺便说一下

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
并将这些时间间隔内的所有值相加

输出:

Timestamp   TotalValue  Price
1           8           1
3           11          4
7           14          2.5
10          NULL        3
如果要过滤掉没有订单的行,只需添加WHERE子句即可

如果要关闭最后一个间隔,您还可以指示LEAD window函数的默认值,如:

LEAD(pt.[Timestamp], 1, 100) 
我猜在制作中会是这样的:

LEAD(pt.[Timestamp], 1, GETDATE()) 
你可以用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%

请从fiddle发布所有表DDL,并在此处提供数据示例。SQLFiddle只是帮助我们帮助您的另一个工具。另外还有一个是为了感谢您的努力。很好,我将在实际数据上尝试这些解决方案。无论如何谢谢你,你需要排除最后一行10-空
LEAD(pt.[Timestamp], 1, GETDATE()) 
;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