web-dev-qa-db-ja.com

注文間の平均日数を計算する

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
「)」付近の構文が正しくありません。

4
Zahir

いくつかの問題:

  • 顧客ごとに平均を取ることを試みていますが、顧客ごとにグループ化しているわけではありません。
  • 日時の暗黙的な計算(_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;
_
6
Aaron Bertrand

クエリを簡略化する方法-注文日間の平均遅延のみが必要な場合-は、最初と最後の注文の日付と各顧客の注文数のみが必要であることを特定することです。顧客の注文が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 ;
5
ypercubeᵀᴹ

これは基本的には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
0
paparazzo