2016-05-30 43 views
3

我爲我的問題準備了一個sql小提琴。 Here it is這裏有一個工作代碼。我在問是否存在我沒​​有想到的替代解決方案。GroupBy關於另一張桌子上的記錄間隔

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 | 

在這裏,我的第一臺[產品]包含時間戳不同的產品價值。第二個表[PriceTable]包含不同時間間隔的價格。一個給定的價格是有效的,直到設置新的價格。因此,時間戳1的價格對於時間戳1和2的產品有效。

我試圖根據給定價格獲得產品總數。小提琴上的SQL產生了我所期望的。

有更聰明的方法來獲得相同的結果嗎?

順便說一句,我使用的SQLServer 2014

+1

請從小提琴發佈所有表格DDL並在此處提供數據示例。 'SQLFiddle'只是幫助我們幫助你的另一個工具。 – sagi

+3

加上一個爲你的努力..好 – tharif

+0

我將嘗試這些解決方案的實際數據。無論如何謝謝 –

回答

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

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()) 
+0

你需要排除最後一行(10 - null) – Ash

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 

它很容易取消了很多derstand和執行計劃與您的查詢(約10%)相比更便宜

相關問題