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');
私はこのクエリを試しました:
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)
ただし、これにより次の結果が得られます。
メッセージ102、レベル15、状態1
「)」付近の構文が正しくありません。
いくつかの問題:
OrderDate-PriorDate
_)はお勧めできません( 日付またはdatetime2 で試してください)-DATEDIFF
を使用してください。SELECT 5/2;
_を試してください。少なくとも1つの入力を10進数に暗黙的に(_*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;
_
結果:
_CustomerID AvgLag
---------- ------
100 7.50
_
もちろん、すべての顧客の平均が必要な場合は、WHERE
句を省略します。ただし、本当に1人の顧客だけが必要な場合は、出力に顧客を本当に必要としないので、クエリを少し調整して_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;
_
クエリを簡略化する方法-注文日間の平均遅延のみが必要な場合-は、最初と最後の注文の日付と各顧客の注文数のみが必要であることを特定することです。顧客の注文が11件あり、最初の注文から最後の注文までの年が1年の場合、平均は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 ;
これは基本的にはypercube +1と同じだと思います(見ていません)
select CustomerID
, cast(DATEDIFF(dd, min(OrderDate), max(OrderDate)) as decimal) / (count(*) - 1) as [avgDayDelta], count(*)
from #Orders
group by CustomerID
having count(*) > 1