1

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

谢谢!

数据

+---------------------+-------------+--------------+
|         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

4 回答 4

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')
于 2012-05-23T16:37:45.443 回答
1
STDEV( isnull( ProductCount , 0 ) ) 
于 2012-05-23T16:28:04.147 回答
1

建立一个小时表和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
于 2012-05-23T17:09:35.200 回答
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)
于 2015-04-08T23:12:54.843 回答