我有一个数据库表,其中包含从供应商处收集的产品的收集数据,我需要使用Oracle SQL查询生成该供应商的月初至今生产数据的估算值。每天可以有多个集合,每个集合可以包含多天生成的产品。
以下是原始收集数据的示例:
Date Volume ColectionNumber ProductionDays 2011-08-22 500 1 2 2011-08-22 200 2 2 2011-08-20 600 1 2
创建一个月初至今的估算是棘手的,因为该月的第一天可能有两天的生产收集。该收集量中只有一部分实际上归因于当月。
如何编写查询以产生此估算值?
我的直觉是,我应该能够创建一个数据库视图,通过在同一天汇总集合并在整个产品生成天数内分配集合量,将原始数据转换为估计的每日生产数据。这将允许我编写一个简单的查询来查找月初至今的生产数据。
以下是上述收集数据在转换为估计的每日生产数据后的样子:
Date VolumeEstimate 2011-08-22 350 2011-08-21 350 2011-08-20 300 2011-08-19 300
我是否在正确的轨道上?如果是这样,如何实施?我完全不知道如何在SQL中进行这种类型的转换。如果没有,那么更好的方法是什么?
注意:我无法在应用程序代码中进行此计算,因为这将需要我们无法承受的重大代码更改。
答案 0 :(得分:1)
试
CREATE TABLE TableA (ProdDate DATE, Volume NUMBER, CollectionNumber NUMBER, ProductionDays NUMBER);
INSERT INTO TableA VALUES (TO_DATE ('20110822', 'YYYYMMDD'), 500, 1, 2);
INSERT INTO TableA VALUES (TO_DATE ('20110822', 'YYYYMMDD'), 200, 2, 2);
INSERT INTO TableA VALUES (TO_DATE ('20110820', 'YYYYMMDD'), 600, 1, 2);
COMMIT;
CREATE VIEW DailyProdVolEst AS
SELECT DateList.TheDate, SUM (DateRangeSums.DailySum) VolumeEstimate FROM
(
SELECT ProdStart, ProdEnd, SUM (DailyProduction) DailySum
FROM
(
SELECT (ProdDate - ProductionDays + 1) ProdStart, ProdDate ProdEnd, CollectionNumber, VolumeSum/ProductionDays DailyProduction
FROM
(
Select ProdDate, CollectionNumber, ProductionDays, Sum (Volume) VolumeSum FROM TableA
GROUP BY ProdDate, CollectionNumber, ProductionDays
)
)
GROUP BY ProdStart, ProdEnd
) DateRangeSums,
(
SELECT A.MinD + MyList.L TheDate FROM
(SELECT MIN (ProdDate - ProductionDays + 1) MinD FROM TableA) A,
(SELECT LEVEL - 1 L FROM DUAL CONNECT BY LEVEL <= (SELECT Max (ProdDate) - MIN (ProdDate - ProductionDays + 1) + 1 FROM TableA)) MyList
) DateList
WHERE DateList.TheDate BETWEEN DateRangeSums.ProdStart AND DateRangeSums.ProdEnd
GROUP BY DateList.TheDate;
视图DailyProdVolEst
动态地为您提供了您描述的结果......虽然适用了一些“约束”:
ProdDate
和CollectionNumber
的组合应该是唯一的。ProductionDays
需要&gt;所有行都为0 编辑 - 根据要求提供的评论:
此查询的工作原理:
它找出表中最小的+最大日期是什么,然后构建行,每行是该范围内的日期(DateList
)...这与包含每日总和的行列表相匹配ProdDate开始/结束(DateRangeSums
)的独特组合,并在日期级别汇总。
SUM (DateRangeSums.DailySum)
和SUM (DailyProduction)
做了什么?
两者总结 - SUM (DateRangeSums.DailySum)
总结了部分重叠日期范围的情况,SUM (DailyProduction)
总结了一个日期范围内如果有多个CollectionNumber
。如果没有SUM
,则不需要GROUP BY
。
答案 1 :(得分:0)
我认为UNION查询可以帮到你。您没有在示例中使用CollectionNumber字段,因此我将其从下面的示例中排除。
类似于以下查询的东西应该有效(免责声明:目前我无法访问我的oracle db):
SELECT Date, SUM(Volume) VolumeEstimate
FROM
(SELECT Date, SUM(Volume / ProductionDays) Volume
FROM [Table]
GROUP BY Date
UNION
SELECT (Date - 1) Date, SUM(Volume / 2)
WHERE ProductionDays = 2
GROUP BY Date - 1)
GROUP BY Date
答案 2 :(得分:0)
听起来你想做的就是白天总结,然后使用计数表来划分结果。
这是一个runnable example,其中包含T-SQL方言中的数据:
DECLARE @tbl AS TABLE (
[Date] DATE
, Volume INT
, ColectionNumber INT
, ProductionDays INT);
INSERT INTO @tbl
VALUES ('2011-08-22', 500, 1, 2)
, ('2011-08-22', 200, 2, 2)
, ('2011-08-20', 600, 1, 2);
WITH Numbers AS (SELECT 1 AS N UNION ALL SELECT 2 AS N)
,AssignedVolumes AS (
SELECT t.*
, t.Volume / t.ProductionDays AS PerDay
, DATEADD(d, 1 - n.N, t.[Date]) AS AssignedDate
FROM @tbl AS t
INNER JOIN Numbers AS n
ON n.N <= t.ProductionDays
)
SELECT AssignedDate
, SUM(PerDay)
FROM AssignedVolumes
GROUP BY AssignedDate;
我打了一个简单的数字表,其中只有1和2来执行枢轴。通常,您将拥有一个包含数百万个数字的表格。
对于Oracle,您唯一需要更改的是DATEADD。