如何使用SQL Server计算缺少数据的标准差

时间:2012-05-23 16:18:27

标签: sql sql-server-2008 tsql statistics

我知道SQL Server是STDEV和STDEVP的聚合函数。但是,在我的具体情况下,我的表缺少数据。表中显示了每小时的产品库存。当缺少一个小时时,这意味着库存为0.假设我想计算一整天2012-01-01产品“香蕉”数量的标准差,我该怎么做? / p>

谢谢!

数据

+---------------------+-------------+--------------+
|         Date        | ProductName | ProductCount |
+---------------------+-------------+--------------+
| 2012-01-01 00:00:00 |    Banana   |    15000     |
| 2012-01-01 01:00:00 |    Banana   |    16000     |
| 2012-01-01 02:00:00 |    Banana   |    17000     |
| 2012-01-01 05:00:00 |    Banana   |    12000     |
| 2012-01-01 00:00:00 |    Apple    |     5000     |
| 2012-01-01 05:00:00 |    Apple    |     6000     |
+---------------------+-------------+--------------+

SQL

CREATE TABLE ProductInventory (
    [Date]  DATETIME,
    [ProductName] NVARCHAR(50),
    [ProductCount] INT
)

INSERT INTO ProductInventory VALUES ('2012-01-01 00:00:00', 'Banana', 15000)
INSERT INTO ProductInventory VALUES ('2012-01-01 01:00:00', 'Banana', 16000)
INSERT INTO ProductInventory VALUES ('2012-01-01 02:00:00', 'Banana', 17000)
INSERT INTO ProductInventory VALUES ('2012-01-01 05:00:00', 'Banana', 12000)
INSERT INTO ProductInventory VALUES ('2012-01-01 00:00:00', 'Apple', 5000)
INSERT INTO ProductInventory VALUES ('2012-01-01 05:00:00', 'Apple', 6000)

4 个答案:

答案 0 :(得分:2)

你可以使用CTE功能(我让你搜索它)来获得从1到24的小时。

但是创建一个“小时表”可能很容易,值为0到23。

假设你有一个带小时字段的小时表

select stdev(coalesce(pi.ProductCount, 0))
from hours h
left join ProductInventory pi on DATEPART(hh, pi.Date) = h.hour
where coalesce(pi.ProductName, 'Banana') = 'Banana'
and (pi.Date is null or (Convert(char(8), pi.Date, 112))='20120101')

答案 1 :(得分:1)

STDEV(isnull(ProductCount,0))

答案 2 :(得分:1)

为Products表构建一个小时表LEFT JOIN

DECLARE @h TABLE(hr DATETIME);
DECLARE @StartTime DATETIME='1/1/2012 00:00:00';
DECLARE @EndTime DATETIME='1/1/2012 23:00:00';
DECLARE @HourCount INT = DATEDIFF(HOUR,@StartTime,@EndTime)+1;
DECLARE @Product VARCHAR(30) = 'Banana';

INSERT INTO @h
SELECT TOP(@HourCount) DATEADD(HOUR,ROW_NUMBER()OVER(ORDER BY message_id)-1,@StartTime)
FROM sys.messages;

SELECT [ProductName]=ISNULL([ProductName],@Product)
, sd=STDEV(ISNULL([ProductCount],0))
FROM @h h
LEFT JOIN ProductInventory i ON h.hr = i.[Date]
WHERE ISNULL([ProductName],@Product)=@Product
GROUP BY ISNULL([ProductName],@Product);

结果:

ProductName                                        sd
-------------------------------------------------- ----------------------
Banana                                             5763.45307123671

答案 3 :(得分:1)

生成0记录的成本相当高,尤其是在使用大量数据时。您还可以使用此查询来运行计算,而无需为缺失的零创建其他记录:

select #ProductInventory.ProductName, 
    sqrt((sum(Power((DataSum / TotalDataPoints - ProductCount), 2)) + ZeroDataPoints * power(DataSum / TotalDataPoints, 2))/(TotalDataPoints-1)) stdDev,
    sqrt((sum(Power((DataSum / TotalDataPoints - ProductCount), 2)) + ZeroDataPoints * power(DataSum / TotalDataPoints, 2))/(TotalDataPoints)) stdDevP
from #ProductInventory
join
    (
    select ProductName, 
    convert(float,SUM(ProductCount)) DataSum,
    convert(float,datediff(hour, min(Date), MAX(date)) + 1) TotalDataPoints,
    convert(float,datediff(hour, min(Date), MAX(date)) + 1 - COUNT(ProductCount)) ZeroDataPoints
    from #ProductInventory
    group by ProductName
    ) Aggregates
on #ProductInventory.ProductName = Aggregates.ProductName
Group by #ProductInventory.ProductName, DataSum, TotalDataPoints, ZeroDataPoints

这假设您的第一个和最后一个数据点在集合中。因此,如果您想要使用整个24小时工作日,则必须确保第一个和最后一个值(如果不存在)的集合中至少添加了0个数据点。例如,在这种情况下,您可以在运行上述查询之前使用此代码添加日终点:

INSERT INTO #ProductInventory VALUES ('2012-01-01 23:00:00', 'Banana', 0)
INSERT INTO #ProductInventory VALUES ('2012-01-01 23:00:00', 'Apple', 0)