查询用于报告的事件表

mg1*_*075 5 query sql-server-2000 reporting

背景 (用单词问题掩盖了一个现实世界的问题)
Farmer Brown 在加利福尼亚州有一个桃园,向全国各地运送数十万个桃子。当一批桃子到达目的地时,送货员会检查桃子并保留所有未通过检查的桃子。

当检验不合格的桃子运回 Farmer Brown's 农场后,Farmer Brown's Peach Hospital 将修复桃子缺陷,并与下一批桃子一起重新发货。如果原来的桃子再次检查不合格,只要桃子是可挽救的,它们就会经历同样的过程。

桃子医院很贵,运费也很贵,所以Farmer Brown开始思考,“对于我在任何时间范围内运送的桃子,我总共运送了多少?在总数中,第二次运送了多少?对于第三次(或更多)?”

在高层次上,桃子发货跟踪表(在 SQL Server 2000 数据库上)有超过900 万条不同类型发货的记录,看起来(大致)类似于:

ShipmentDate   PeachID    Shipment Type
8/10/2005         7112      Shipment to Customer
7/15/2007         8798      Shipment to Customer
4/3/2009          8798      Shipment to Customer
4/15/2009         8798      Shipment to Customer
4/21/2009         8798      Shipment to Customer
4/21/2009         145751    Shipment to Customer
4/22/2009         7112      Shipment to Customer
4/22/2009         12121     Shipment to Customer
4/25/2009         8798      Shipment to Customer
5/12/2009         8798      Shipment to Customer
Run Code Online (Sandbox Code Playgroud)

如果我们尝试返回 Farmer Brown 正在寻找的样本,结果将如下所示:

给定以下参数:
StartDate = 4/1/2009, EndDate = 4/30/2009

结果
-- 简单的部分
运送给客户的桃子总数:100,000
(PeachID 8798 占总数的 4。PeachID 7112 占总数的 1。)

-- 乱七八糟的部分
第二次发货的桃子总数:5000个
(PeachID 8798贡献了1个。PeachID 7112贡献了1个。)

第 3 次(或更多)次发货的桃子总数:800
(PeachID 8798 占总数的 2。)

问题
构建这些数据的保存表(每天刷新一次 - 实时并不重要)的最有效方法是什么,以便在检索 Farmer Brown 请求的数据时,可以快速返回数据?我在想,如果从 Farmer Brown 开业日开始到现在的发货按天汇总到一个或多个保存表中,然后在任何日期范围参数上执行汇总,proc 的运行速度将比查询 Shipments 表及其数百万条记录。

如果我没有足够清楚地解释情况,我深表歉意。我真的很感激外界对此的看法。

Jon*_*des 1

我会PriorShipments向事实表添加一个字段。您将有很多行,但ShipDate字段上的聚类应该非常有效,并且查询也非常简单。

CREATE TABLE #Shipments
(
ID  INT NOT NULL,
ShipDate    DATE NOT NULL,
PRIMARY KEY (ID, ShipDate),
CustomerID  INT NOT NULL,
PriorShipments  INT NOT NULL DEFAULT 0
)
INSERT INTO #Shipments (ShipDate, ID, CustomerID) VALUES
    ('2005-08-10',   7112,  942), 
    ('2007-07-15',   8798,  160), 
    ('2009-04-03',   8798,  160), 
    ('2009-04-15',   8798,  160), 
    ('2009-04-21',   8798,  160), 
    ('2009-04-21', 145751,  139), 
    ('2009-04-22',   7112,  942), 
    ('2009-04-22',  12121, 1015), 
    ('2009-04-25',   8798,  160), 
    ('2009-05-12',   8798,  160)

UPDATE RS
SET PriorShipments = NumPrev
FROM #Shipments AS RS
    INNER JOIN
        (
        SELECT S1.ID, S1.ShipDate, COUNT(*) AS NumPrev
        FROM #Shipments AS S1
            INNER JOIN #Shipments AS S2 ON S1.ID = S2.ID AND S2.ShipDate < S1.ShipDate
        GROUP BY S1.ID, S1.ShipDate
        ) AS Seq ON RS.ID = Seq.ID AND RS.ShipDate = Seq.ShipDate

-- If Farmer Brown gets a Dept of Agriculture grant to upgrade his database, he could instead use:
UPDATE RS
SET PriorShipments = Seq - 1
FROM #Shipments AS RS
    INNER JOIN
        (
        SELECT ID, ShipDate, ROW_NUMBER() OVER (PARTITION BY ID ORDER BY ShipDate) AS Seq
        FROM #Shipments
        ) AS Seq ON RS.ID = Seq.ID AND RS.ShipDate = Seq.ShipDate

-- The good part
SELECT COUNT(*) FROM #Shipments WHERE ShipDate BETWEEN '2009-04-01' AND '2009-04-30'
SELECT COUNT(*) FROM #Shipments WHERE ShipDate BETWEEN '2009-04-01' AND '2009-04-30' AND PriorShipments = 1
SELECT COUNT(*) FROM #Shipments WHERE ShipDate BETWEEN '2009-04-01' AND '2009-04-30' AND PriorShipments >= 2
Run Code Online (Sandbox Code Playgroud)

您可以预先汇总一下,只要农夫布朗永远不会关心他将桃子运送到哪些农场即可。

搬到乡下去,要吃我很多桃子......