Neo*_*tim 7 sql-server aggregate sql-server-2012 window-functions
我需要显示产品在过去 4 次生产中的平均重量。除了示例之外,我不知道如何最好地描述它:让我们想象一下,我有下表按创建日期列出了产品,以及当天产品的平均重量:
+---------+---------+--------+
| Product | Date | Weight |
+---------+---------+--------+
| 900000 | Jan 1 | 20.0 |
| 900000 | March 3 | 12.2 |
| 900000 | July 6 | 15.0 |
| 900000 | July 7 | 14.0 |
| 900000 | Aug 6 | 3.0 |
| 800000 | June 2 | 14.0 |
| 800000 | June 3 | 12.0 |
+---------+---------+--------+
Run Code Online (Sandbox Code Playgroud)
我正在寻找的最终结果是添加一个列,其中包含产品运行的最后 4 个日期的平均重量,因此如下所示:
+---------+---------+--------+----------------+
| Product | Date | Weight | Average Weight |
+---------+---------+--------+----------------+
| 900000 | Jan 1 | 20.0 | NULL |
| 900000 | March 3 | 12.2 | NULL |
| 900000 | July 6 | 15.0 | NULL |
| 900000 | July 7 | 14.0 | NULL |
| 900000 | Aug 6 | 3.0 | 15.3 | Jan1+Mar3+July6+July7/4
| 900000 | Aug 8 | 13.0 | 11.05 | Mar3+July6+July7+Aug6/4
| 800000 | June 2 | 14.0 | NULL |
| 800000 | June 3 | 12.0 | NULL |
| 800000 | June 4 | 12.0 | NULL |
| 800000 | June 5 | 12.0 | NULL |
| 800000 | June 6 | 12.0 | 12.5 | etc...
+---------+---------+--------+----------------+
Run Code Online (Sandbox Code Playgroud)
NULL 就在那里,因为在此示例中,您无法计算过去 4 次运行的平均值,因为数据不存在。
任何人都可以指出我需要做这样的事情的方向吗?
Pau*_*ite 10
CREATE TABLE dbo.Thing
(
Product integer NOT NULL,
TheDate date NOT NULL,
TheWeight decimal(5, 1) NOT NULL
);
INSERT dbo.Thing
(Product, TheDate, TheWeight)
VALUES
(900000, CONVERT(date, '20160101', 112), 20.0),
(900000, '20160303', 12.2),
(900000, '20160706', 15.0),
(900000, '20160707', 14.0),
(900000, '20160806', 3.0 ),
(900000, '20160808', 13.0 ),
(800000, '20160602', 14.0),
(800000, '20160603', 12.0),
(800000, '20160604', 12.0),
(800000, '20160605', 12.0),
(800000, '20160606', 12.0);
Run Code Online (Sandbox Code Playgroud)
这里的总体思路是使用 SQL Server 2012 及更高版本中可用的扩展窗口聚合函数。
唯一的问题是,AVG如果窗口小于所需的四行,则不会在窗口上返回 null。为了解决这个问题,我们还使用 计算在窗口中找到的行数COUNT。CASE如果窗口少于四行,则可以使用简单的表达式返回空值:
SELECT
T.Product,
T.TheDate,
T.TheWeight,
[Average Weight] =
CASE
WHEN
4 > COUNT_BIG(*) OVER (
PARTITION BY T.Product
ORDER BY T.Product, T.TheDate
ROWS BETWEEN 4 PRECEDING
AND 1 PRECEDING
)
THEN NULL
ELSE
AVG(T.TheWeight) OVER (
PARTITION BY T.Product
ORDER BY T.Product, T.TheDate
ROWS BETWEEN 4 PRECEDING
AND 1 PRECEDING
)
END
FROM dbo.Thing AS T
ORDER BY
T.Product,
T.TheDate;
Run Code Online (Sandbox Code Playgroud)
在Stack Exchange Data Explorer上运行查询
这是一个滚动平均值,它是 SQL Server 2012 和更新版本中的一个窗口函数。你可以这样解决:
SELECT Product, [Date], Weight,
(CASE WHEN _runningCount>=4
THEN _runningTotal/4.0
END) AS [Average weight]
FROM (
SELECT Product, [Date], Weight,
SUM(Weight) OVER (
PARTITION BY Product
ORDER BY [Date]
ROWS BETWEEN 4 PRECEDING AND 1 PRECEDING) AS _runningTotal,
SUM(1) OVER (
PARTITION BY Product
ORDER BY [Date]
ROWS BETWEEN 4 PRECEDING AND 1 PRECEDING) AS _runningCount
FROM theTable
) AS sub;
Run Code Online (Sandbox Code Playgroud)
以下是关键点:
OVER ()子句描述了聚合(在本例中为 SUM)发生在一个窗口中。在我们的例子中,我们想要聚合当前产品(分区)的最近前四行,按日期排序。SUM(1) 作为计数。sub._runningCount是 4 或更多,我们可以将最近四行的运行总数除以 4,否则,返回NULL。如果您想在任何给定时间返回运行总计(也包括前几个日期),您可以将 更改为CASE:
SELECT ...
_runningTotal/_runningCount AS [Average weight]
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
404 次 |
| 最近记录: |