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 表及其数百万条记录。
如果我没有足够清楚地解释情况,我深表歉意。我真的很感激外界对此的看法。
我会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)
您可以预先汇总一下,只要农夫布朗永远不会关心他将桃子运送到哪些农场即可。
搬到乡下去,要吃我很多桃子......