【问题标题】:Generate a row per minute of the day from a sparsely populated database table从人口稀少的数据库表中每分钟生成一行
【发布时间】:2009-10-29 17:19:42
【问题描述】:

我有一个表格,其中填充了在一天中(基本上)随机点插入的带有时间戳的行。

我需要以每分钟 1 行的方式生成运行总计(因此一天中总会有 24 * 60 行),例如

Date                Quantity    Running Total
2009-10-29 06:30           1                1
2009-10-29 06:31           5                6
2009-10-29 06:32           10              16  
2009-10-29 06:33           11              27   
2009-10-29 06:34           22              49

... ...

对最好的方法有什么想法吗? 一个 SQL 查询将是理想的但不是必需的,性能相当重要(在包含 500k 行的表上不到 5 秒,其中 70k 对此查询感兴趣)

我的最终解决方案(或多或少)。

实际情况是这样的。我有两个表,其中一个包含与 Fills 表具有 1:n 关系的 Orders。

我需要显示交易日每分钟的运行平均价格和累计总价

DECLARE @StartDate AS DATETIME, @EndDate AS DATETIME
SET @StartDate = '2009-10-28';
SET @EndDate = '2009-10-29';

-- Generate a Temp Table containing all the dates I'm interested in
WITH DateIntervalsCTE AS
(
 SELECT 0 i, @StartDate AS Date
 UNION ALL
 SELECT i + 1, DATEADD(minute, i, @StartDate )
 FROM DateIntervalsCTE 
 WHERE DATEADD(minute, i, @StartDate ) < @EndDate
)
SELECT DISTINCT Date 
INTO #Dates
FROM DateIntervalsCTE
OPTION (MAXRECURSION 32767);

SELECT 
 d.Date
 , mo3.symbol
 , ISNULL(SUM(mf.Quantity),0) AS CumulativeTotal
 , ROUND(ISNULL(SUM(mf.Quantity * mf.Price)/SUM(mf.Quantity),0),4) AS AveragePrice
FROM 
 #Dates AS d
 CROSS JOIN (
    SELECT DISTINCT mo2.Symbol, mo2.OrderID 
    FROM 
     Orders AS mo2 
     INNER JOIN Fills AS mf2 ON mo2.OrderID = mf2.OrderID
    WHERE CONVERT(DATETIME,CONVERT(CHAR(10),mf2.FillDate,101)) = @StartDate
    ) AS mo3
 LEFT JOIN Fills AS mf ON mo3.OrderID = mf.OrderID AND CONVERT(DATETIME,CONVERT(CHAR(16),mf.FillDate,120)) < = d.Date
WHERE
 d.Date >= DATEADD(mi,390, @StartDate) -- 06:30
 AND d.Date <= DATEADD(mi,780, @StartDate) -- 13:00
GROUP BY d.Date, mo3.symbol
ORDER BY mo3.Symbol, d.Date

我还没有完成所有的测试,但这看起来可以解决问题,感谢您的帮助!

【问题讨论】:

标签: sql-server-2005


【解决方案1】:

确保日期列上有索引并且性能应该是合理的。

SELECT t.Date,
COUNT(*) AS Quantity,
(SELECT COUNT(*) FROM Table WHERE Date < t.Date) AS RunningTotal
FROM Table t
GROUP BY t.Date

可以非常快速地完成每分钟填充一行的表格,如下所示:

DECLARE @StartDate smalldatetime
DECLARE @EndDate smalldatetime

SET @StartDate = '1 jan 2009' --MIN(TimeStamp) FROM Table
SET @EndDate = '2 jan 2009' --MAX(TimeStamp) FROM Table

SET @StartDate = DATEADD(minute,-DATEPART(minute,@StartDate),@StartDate)
SET @EndDate = DATEADD(minute,-DATEPART(minute,@EndDate),@EndDate)


; WITH DateIntervalsCTE AS
(
SELECT 0 i, @startdate AS Date
UNION ALL
SELECT i + 1, DATEADD(minute, i, @startdate )
FROM DateIntervalsCTE 
WHERE DATEADD(minute, i, @startdate ) <= @enddate
)
SELECT DISTINCT Date FROM DateIntervalsCTE
OPTION (MAXRECURSION 32767);

由于递归限制,您只需要

您现在只需将两者合并,使用临时表保存数据似乎是最快的

DECLARE @StartDate smalldatetime
DECLARE @EndDate smalldatetime
DECLARE @t TABLE (Date smalldatetime,Quantity int,RunningTotal int)
SET @StartDate = '1 jan 2009' --MIN(TimeStamp) FROM Table
SET @EndDate = '2 jan 2009' --MAX(TimeStamp) FROM Table

SET @StartDate = DATEADD(minute,-DATEPART(minute,@StartDate),@StartDate)
SET @EndDate = DATEADD(minute,-DATEPART(minute,@EndDate),@EndDate)


; WITH DateIntervalsCTE AS
(
SELECT 0 i, @startdate AS Date
UNION ALL
SELECT i + 1, DATEADD(minute, i, @startdate )
FROM DateIntervalsCTE 
WHERE DATEADD(minute, i, @startdate ) <= @enddate
)
INSERT INTO @t (Date) 
SELECT DISTINCT Date FROM DateIntervalsCTE
OPTION (MAXRECURSION 32767);

UPDATE t SET Quantity = (SELECT COUNT(d.TimeStamp) FROM Table d WHERE Date = t.date)
from @t t

update t2 set runningtotal = (SELECT SUM(Quantity) FROM @t WHERE date <= t2.date)
from @t t2

select * from @t

【讨论】:

  • 想一想,必须有一种 CTE 方法才能更好地做到这一点。
  • 谢谢,这肯定解决了运行总部分,但我不是每分钟都有一行,通常我会在一秒钟内得到 10 行,然后几分钟内什么也没有
  • 那么你需要零来表示没有行的分钟吗?
  • 谢谢!这足以让我弄清楚其余部分,因为我已经有一段时间没有写过这样一个令人费解的查询了。等我测试完我会在这里贴出来
【解决方案2】:

您肯定会想要使用 group by。困难的(ish)部分是它将是合成的,这意味着您必须自己创建它。有很多方法可以做到这一点

GROUP BY year(yourdate)、month(yourdate)、day(yourdate) 等...

除了我不记得是否有 hours() 和 minutes() 函数不在我的脑海中。

您也可以使用datepart 函数。

然后,您可以将所有这些放在一列中以获得漂亮的标签。

【讨论】:

    猜你喜欢
    • 2020-05-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多