Je voudrais calculer le nombre moyen de jours entre plusieurs dates de commande à partir d'un tableau appelé Commandes. Pour chaque CustomerID, quel est le nombre moyen de jours entre les commandes. Le tableau exemple est comme ci-dessous ( img ):
CREATE TABLE #Orders(CustomerID int, OrderDate datetime);
INSERT #Orders(CustomerID, OrderDate) VALUES
(100,'20170114'),(100,'20170123'),(100,'20170129'),
(101,'20170202'),(101,'20170212');
J'ai essayé cette requête:
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)
Cependant, cela donne:
Msg 102, niveau 15, état 1
Syntaxe incorrecte près de ')'.
Plusieurs problèmes:
OrderDate-PriorDate
) Ne sont pas une bonne idée ( essayez cela avec date ou datetime2 ) - utilisez DATEDIFF
.SELECT 5/2;
. Vous devez convertir au moins une entrée en décimale, soit implicitement (*1.0
) Ou explicitement (CONVERT(), TRY_CONVERT(), CAST(), etc.
). Explicit vous permet de contrôler les décimales dans certains cas.LAG()
n'était pas terminée - alors que la valeur par défaut est 1, je pense qu'il est bon d'être explicite que vous voulez la ligne précédente.SELECT ... FROM (<subquery>)
, cette sous-requête doit être nommée, vous devez donc utiliser quelque chose comme SELECT ... FROM (<subquery>) AS x;
par exemple .Essayez ce qui suit:
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;
Résultats:
CustomerID AvgLag
---------- ------
100 7.50
Bien sûr, si vous voulez la moyenne pour tous les clients, laissez simplement la clause WHERE
. Mais si vous ne voulez vraiment qu'un seul client, vous n'avez pas vraiment besoin du client dans la sortie, vous pouvez donc ajuster un peu la requête pour vous débarrasser du GROUP BY
(Paramétrons l'ID client tout en nous y sommes):
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;
Un moyen de simplifier la requête - si vous n'avez besoin que du délai moyen entre les dates de commande - consiste à identifier que vous n'avez besoin que des dates des première et dernière commandes et du nombre de commandes pour chaque client. Si vous avez 11 commandes pour un client et un an entre la première et la dernière commande, la moyenne est de 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 ;
Je pense que c'est fondamentalement la même chose que ypercube +1 (je ne l'ai pas vu)
select CustomerID
, cast(DATEDIFF(dd, min(OrderDate), max(OrderDate)) as decimal) / (count(*) - 1) as [avgDayDelta], count(*)
from #Orders
group by CustomerID
having count(*) > 1