Za*_*hir 4 sql-server t-sql sql-server-2014
我想从一个名为 Orders 的表中计算几个订单日期之间的平均天数。对于每个 CustomerID,订单之间的平均天数是多少。示例表如下(img):
CREATE TABLE #Orders(CustomerID int, OrderDate datetime);
INSERT #Orders(CustomerID, OrderDate) VALUES
(100,'20170114'),(100,'20170123'),(100,'20170129'),
(101,'20170202'),(101,'20170212');
Run Code Online (Sandbox Code Playgroud)
我试过这个查询:
SELECT CustomerID, AVG(OrderDate - PriorDate)
FROM (SELECT CustomerID, OrderDate
, LAG(OrderDate) OVER (PARTITION BY CustomerID ORDER BY OrderDate) as PriorDate
FROM #Orders where CustomerID = 100)
Run Code Online (Sandbox Code Playgroud)
但是,这会产生:
消息 102,级别 15,状态 1
')' 附近的语法不正确。
几个问题:
OrderDate-PriorDate
) 的隐式数学不是一个好主意(尝试使用 date 或 datetime2) - 使用DATEDIFF
。SELECT 5/2;
。您需要将至少一个输入转换为小数,隐式 ( *1.0
) 或显式 ( CONVERT(), TRY_CONVERT(), CAST(), etc.
)。Explicit 允许您在某些情况下控制小数位。LAG()
未完成 - 虽然默认值为 1,但我认为最好明确表示您想要前一行。SELECT ... FROM (<subquery>)
,该子查询需要命名,因此您需要使用类似SELECT ... FROM (<subquery>) AS x;
的内容。请尝试以下操作:
SELECT
CustomerID,
AvgLag = AVG(CONVERT(decimal(7,2), DATEDIFF(DAY, PriorDate, OrderDate)))
FROM
(
SELECT CustomerID, OrderDate, PriorDate = LAG(OrderDate,1)
OVER (PARTITION BY CustomerID ORDER BY OrderDate)
FROM #Orders
WHERE CustomerID = 100
) AS lagged
GROUP BY CustomerID;
Run Code Online (Sandbox Code Playgroud)
结果:
CustomerID AvgLag
---------- ------
100 7.50
Run Code Online (Sandbox Code Playgroud)
当然,如果您想要所有客户的平均值,只需省略该WHERE
条款。但是,如果您真的只想要一个客户,那么您实际上并不需要输出中的客户,因此您可以稍微调整查询以摆脱GROUP BY
(让我们在处理时参数化客户 ID) :
DECLARE @CustomerID int = 100;
SELECT AvgLag = AVG(Lag), CustomerID = @CustomerID -- you may not need this
FROM
(
SELECT Lag = CONVERT(decimal(7,2), DATEDIFF(DAY, LAG(OrderDate,1)
OVER (PARTITION BY CustomerID ORDER BY OrderDate), OrderDate))
FROM #Orders
WHERE CustomerID = @CustomerID
) AS Lagged;
Run Code Online (Sandbox Code Playgroud)
一种简化查询的方法 - 如果您只需要订单日期之间的平均滞后时间 - 是确定您只需要第一个和最后一个订单的日期以及每个客户的订单数量。如果您有 11 个客户的订单,并且第一个订单和最后一个订单之间有一年的时间,则平均值为365 / 10
.
SELECT
CustomerID,
AvgLag = CASE WHEN COUNT(*) > 1 THEN
CONVERT(decimal(7,2),
DATEDIFF(day, MIN(OrderDate), MAX(OrderDate)))
/ CONVERT(decimal(7,2), COUNT(*) - 1)
ELSE NULL
END
FROM #Orders
GROUP BY CustomerID ;
Run Code Online (Sandbox Code Playgroud)