mg1*_*075 5 sql-server-2008 t-sql
这个问题类似于Running total with count? ,但请允许我进一步解释这个问题。
我使用的是 SQL Server 2008,因此 Aaron Bertrand 描述的游标选项在速度方面似乎是最有前途的。
不过,这里的不同之处在于我必须考虑单个项目的两个日期。因此,给定订单表中的 OrderID 项,OrderID 具有 Opened Date 和 Closed Date。Opened Date 总是填充的,但 Closed Date 可以是NULL。
OrderID OpenedDate ClosedDate
654554 12/1/2011 5/4/2012
678451 12/4/2011 3/2/2012
679565 12/8/2011 5/21/2012
701541 5/23/2012 NULL
...
Run Code Online (Sandbox Code Playgroud)
我需要 - 有效地 - 获取在日期范围内的任何给定日期有多少订单具有我们可以称为“打开”状态的状态。日期范围可能跨越几年。(是的,我确实有一个连续日期的参考表。)
Date CountOfOpenOrders
12/1/2011 175
12/2/2011 178
12/3/2011 195
12/4/2011 192
12/5/2011 191
...
Run Code Online (Sandbox Code Playgroud)
如果您优先考虑的是选择速度,则以下方法可以实现极快的选择。您想要存储两个事件(周期开始和周期结束),而不是存储周期。当时间段开始时,更改列为 1,当时间段结束时,更改列为 -1。如果同一天发生多个事件,则它们必须具有不同的 EventNumberPerDay。RunningTotal 是事件发生后开放周期的数量:
CREATE TABLE dbo.Events(
PeriodId INT NOT NULL,
Change SMALLINT NOT NULL,
ChangeDate DATE NOT NULL,
EventNumberPerDay INT NOT NULL,
RunningTotal INT NOT NULL);
GO
INSERT dbo.Events
( PeriodId ,
Change ,
ChangeDate ,
EventNumberPerDay,
RunningTotal
)
-- first period begins
VALUES ( 1 , 1, '20120801', 1, 1),
-- second period begins on the same day
(2, 1, '20120801', 2, 2),
-- third period begins
(3,1,'20120803',1, 3),
-- second period ends on the same day
(2,-1,'20120803',2, 2),
-- fourth period begins
(4,1,'20120804',1,3),
-- fourth period ends
(4,-1,'20120805',1,2),
-- first period ends
(1, -1, '20120808',1, 1),
-- third period ends
(3, -1, '20120809',1, 0);
GO
Run Code Online (Sandbox Code Playgroud)
您还需要一个日历表:
CREATE TABLE dbo.Calendar([Date] DATE NOT NULL);
GO
INSERT INTO dbo.Calendar([Date])
VALUES('20120801'),
('20120802'),
('20120803'),
('20120804'),
('20120805'),
('20120806'),
('20120807'),
('20120808'),
('20120809'),
('20120810'),
('20120811');
Run Code Online (Sandbox Code Playgroud)
完成后,您的选择将非常简单且快速:
SELECT [Date] ,
coalesce(RunningTotal, 0) AS NumOpenIntervals
FROM dbo.Calendar
OUTER APPLY ( SELECT TOP ( 1 )
RunningTotal
FROM dbo.Events
WHERE ChangeDate <= [Date]
ORDER BY ChangeDate DESC, EventNumberPerDay DESC
) AS t
ORDER BY [Date]
Run Code Online (Sandbox Code Playgroud)
当然,只有当Events表中的数据有效时,这个查询才是正确的。我们可以使用约束来确保 100% 的数据完整性。如果你有兴趣的话我可以解释一下。
另一种选择是将原始数据(即经期)加载到客户端应用程序中 - 在 C++/C#/Java 中,您的问题绝对微不足道。
另一种方法是使用具有快速游标的 RDBMS,例如 Oracle - 这将允许您只编写一个简单的游标并享受良好的性能,但仍然不如我的第一个解决方案。
| 归档时间: |
|
| 查看次数: |
4101 次 |
| 最近记录: |