考虑下表。 Start_Date是将水果收入库存的时间,End_Date是处理它们的时间。请注意,这些日期范围可以重叠。例如,从2014-01-016到2014-02-01,库存中有20个苹果。
+------------------------------------------+
| [HISTORY_TABLE] |
+------------+------------+----------+-----+
| Start_Date | End_Date | Type | QTY |
+------------+------------+----------+-----+
| 2013-12-16 | 2014-02-01 | Apple | 12 |
| 2014-01-16 | 2014-06-01 | Apple | 8 |
| 2014-01-16 | 2014-04-11 | Banana | 5 |
| 2014-03-16 | 2014-04-16 | Banana | 7 |
| 2014-02-16 | 2014-03-01 | Orange | 24 |
| 2013-02-24 | 2014-05-01 | Orange | 2 |
+------------+------------+----------+-----+
我感兴趣的是每种水果类型的平均每月计数。对于1月份的苹果,每日累计苹果总数为:
((12 apples * 15 days) + (20 apples * 16 days) =
(180 apple days + 320 apple days) = 500 apple days
1月份有31天,平均值为:
500 / 31 = 16.13
因此,1月份平均可用的苹果是16.13。
可能存在具有相同日期,类型和数量的水果类型,但假设每个记录是水果的唯一计数。我正在寻找的最终结果将类似于下面(除了所有的水果。)结果中的数字是准确的(至少我认为它们是......我手工计算):
+-----------------------------------------+
| [RESULTS] |
+-------+------+------------+-----+-------+
| Month | Year | Fruit Type | QTY | Avg |
+-------+------+------------+-----+-------+
| 12 | 2013 | Apple | 192 | 6.19 |
| 01 | 2014 | Apple | 500 | 16.13 |
| 02 | 2014 | Apple | 236 | 8.43 |
| 03 | 2014 | Apple | 248 | 8.00 |
| 04 | 2014 | Apple | 240 | 8.00 |
| 05 | 2014 | Apple | 248 | 8.00 |
| 06 | 2014 | Apple | 8 | 0.27 |
+-------+------+------------+-----+-------+
设置初始数据的一些代码:
IF OBJECT_ID('tempdb..#LocalTempFruitTable', 'U') IS NOT NULL
DROP TABLE #LocalTempFruitTable
CREATE TABLE #LocalTempFruitTable(
Start_Date date,
End_Date date,
Type varchar(50),
QTY int)
INSERT INTO #LocalTempFruitTable (Start_Date,End_Date,Type,QTY) VALUES ('2013-12-16','2014-02-01','Apple','12')
INSERT INTO #LocalTempFruitTable (Start_Date,End_Date,Type,QTY) VALUES ('2014-01-16','2014-06-01','Apple','8')
INSERT INTO #LocalTempFruitTable (Start_Date,End_Date,Type,QTY) VALUES ('2014-01-16','2014-04-11','Banana','5')
INSERT INTO #LocalTempFruitTable (Start_Date,End_Date,Type,QTY) VALUES ('2014-03-16','2014-04-16','Banana','7')
INSERT INTO #LocalTempFruitTable (Start_Date,End_Date,Type,QTY) VALUES ('2014-02-16','2014-03-01','Orange','24')
INSERT INTO #LocalTempFruitTable (Start_Date,End_Date,Type,QTY) VALUES ('2013-02-24','2014-05-01','Orange','2')
SELECT * FROM #LocalTempFruitTable
答案 0 :(得分:2)
当您使用日期时,您可以利用这些事实并非如此。单独跟踪它们是完全可行的。创建并填充涵盖所需范围的日期表,例如:
CREATE TABLE date_list ([date] date PRIMARY KEY NOT NULL);
INSERT date_list([date])
SELECT TOP 1000 --This is a quick-and-dirty example
DATEADD(day,ROW_NUMBER() OVER(ORDER BY(SELECT NULL))-1,'2013-01-01')
FROM master.dbo.spt_values;
然后使用它来协助主查询:
WITH daily_tally AS (
SELECT
[date],
[Type],
SUM(Qty) AS [daily_Qty]
FROM date_list
INNER JOIN Results ON [date] BETWEEN [Start_Date] AND [End_Date]
GROUP BY [date],[Type]
)
SELECT
MONTH([date]) AS [month],
YEAR([date]) AS [year],
[Type],
AVG([daily_Qty]) AS [avg_Qty]
FROM daily_tally
GROUP BY MONTH([date]),YEAR([date]),[Type]
答案 1 :(得分:0)
这就是我最终得到的......我们已经创建了一个在两个日期范围之间每天返回的函数:
/****** Object: UserDefinedFunction [dbo].[udf_SpanOfDates] Script Date: 06/09/2014 16:35:52 ******/
SET ANSI_NULLS OFF
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE FUNCTION [dbo].[udf_SpanOfDates]
(
@StartDate Datetime,
@EndDate DateTime
)
RETURNS
@Dates TABLE
(
Date DateTime
, Month_MM integer
, Quarter_QQ integer
, Year_CCYY integer
)
AS
BEGIN
While @StartDate <= @EndDate
begin
insert @Dates
( Date
, Month_MM
, Quarter_QQ
, Year_CCYY
)
Values
( @StartDate
, DATEPART(M,@StartDate)
, DATEPART(Q,@StartDate)
, DATEPART(YYYY,@StartDate)
)
Set @StartDate = @StartDate + 1
end
RETURN
END
GO
通过该功能,我能够做到这一点:
IF OBJECT_ID('tempdb..#LocalTempFruitTable', 'U') IS NOT NULL
DROP TABLE #LocalTempFruitTable
CREATE TABLE #LocalTempFruitTable(
Start_Date date,
End_Date date,
Type varchar(50),
QTY int)
INSERT INTO #LocalTempFruitTable (Start_Date,End_Date,Type,QTY) VALUES ('2013-12-16','2014-02-01','Apple','12')
INSERT INTO #LocalTempFruitTable (Start_Date,End_Date,Type,QTY) VALUES ('2014-01-16','2014-06-01','Apple','8')
INSERT INTO #LocalTempFruitTable (Start_Date,End_Date,Type,QTY) VALUES ('2014-01-16','2014-04-11','Banana','5')
INSERT INTO #LocalTempFruitTable (Start_Date,End_Date,Type,QTY) VALUES ('2014-03-16','2014-04-16','Banana','7')
INSERT INTO #LocalTempFruitTable (Start_Date,End_Date,Type,QTY) VALUES ('2014-02-16','2014-03-01','Orange','24')
INSERT INTO #LocalTempFruitTable (Start_Date,End_Date,Type,QTY) VALUES ('2013-02-24','2014-05-01','Orange','2')
SELECT Month_MM,YEAR_CCYY,Type,SUM(QTY)
FROM dbo.udf_SpanOfDates('2013-12-01', '2014-04-01') sD
INNER JOIN #LocalTempFruitTable fruit
ON (fruit.Start_Date <= sD.Date
AND
(fruit.END_DATE >= sD.Date
OR fruit.End_Date IS NULL)
)
GROUP BY MONTH_MM,YEAR_CCYY,Type
ORDER BY YEAR_CCYY,Month_MM,Type
结果:
MM YEAR Type FruitDays
12 2013 Apple 192
12 2013 Orange 62
1 2014 Apple 500
1 2014 Banana 80
1 2014 Orange 62
2 2014 Apple 236
2 2014 Banana 140
2 2014 Orange 368
3 2014 Apple 248
3 2014 Banana 267
3 2014 Orange 86
4 2014 Apple 8
4 2014 Banana 12
4 2014 Orange 2
此时,计算平均值是学术性的,因为我已经有了月份和“结果日”。
答案 2 :(得分:0)
DECLARE @MyTable TABLE
(
Start_Date DATETIME,
End_Date DATETIME,
Type VARCHAR(20),
Qty DECIMAL(19,6)
)
INSERT INTO @MyTable
( Start_Date, End_Date, Type, Qty )
VALUES
( '12/16/2013', '02/01/2014', 'Apple', 12),
( '01/16/2014', '06/01/2014', 'Apple', 8),
( '01/16/2014', '04/11/2014', 'Banana', 5),
( '03/16/2014', '04/16/2014', 'Banana', 7),
( '02/16/2014', '03/01/2014', 'Orange', 24),
( '02/24/2013', '05/01/2014', 'Orange', 2);
DECLARE @MinDate DATETIME
SELECT @MinDate = MIN(Start_Date) FROM @MyTable
DECLARE @MaxDate DATETIME
SELECT @MaxDate = MAX(End_Date) FROM @MyTable
DECLARE @number_of_numbers INT = 100000;
;WITH
a AS (SELECT 1 AS i UNION ALL SELECT 1),
b AS (SELECT 1 AS i FROM a AS x, a AS y),
c AS (SELECT 1 AS i FROM b AS x, b AS y),
d AS (SELECT 1 AS i FROM c AS x, c AS y),
e AS (SELECT 1 AS i FROM d AS x, d AS y),
f AS (SELECT 1 AS i FROM e AS x, e AS y),
numbers AS
(
SELECT TOP(@number_of_numbers)
ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) AS number
FROM f
)
SELECT d.Type, MONTH(d.CheckDate), YEAR(d.CheckDate), AVG(D.Qty) FROM
(
SELECT c.CheckDate, m.Type, SUM(m.Qty) Qty FROM
(
SELECT DATEADD(DAY, n.number, '1/1/2000') AS CheckDate FROM numbers n
) C
LEFT JOIN @MyTable m
ON c.CheckDate >= m.Start_Date and c.CheckDate <= m.End_Date
WHERE c.CheckDate >= @MinDate AND c.CheckDate <= @MaxDate
GROUP BY c.CheckDate, m.Type
) AS d
GROUP BY d.Type, MONTH(d.CheckDate), YEAR(d.CheckDate)