1

車のテーブルと、さまざまな日付 (毎月 1 日) の走行距離計の読み取り値が与えられた場合、TSQL (理想的には、SQL Server ビューとして使用するため) を記述して "増分" 値を返すにはどうすればよいでしょうか?

言い換えれば、SQL Server での実行合計の計算の逆の操作が必要です。

例:

このテーブルで:

車ID | 日付 | マイレージ
---------------------------
    1 1/1/2000 10000
    1 2000 年 2 月 1 日 11000
    1 2000 年 3 月 1 日 12000
    2 2000 年 1 月 1 日 10000
    2 2000 年 2 月 1 日 11001
    2 2000 年 3 月 1 日 12001
    3 2000 年 1 月 1 日 10000
   ((3, 2/1/2000) のデータポイントがありません)
    3 2000 年 3 月 1 日 12000

次のようなものを返します(詳細/エッジケースは柔軟です):

車ID | 日付 | デルタ
---------------------------
    1 1/1/2000 10000
    1 2000 年 2 月 1 日 1000
    1 2000 年 3 月 1 日 1000
    2 2000 年 1 月 1 日 10000
    2 2000 年 2 月 1 日 1001
    2 2000 年 3 月 1 日 1000
    3 2000 年 1 月 1 日 10000
    3 2000/3/1 2000
4

4 に答える 4

2

これは、SQL 2005 以降で機能するはずです。

WITH cteData As
(
   SELECT
      CarId,
      Date,
      Mileage,
      ROW_NUMBER() OVER (PARTITION BY CarId ORDER BY Date) As RowNumber
   FROM
      dbo.Cars
)
SELECT
   C.CarId,
   C.Date,
   CASE
      WHEN P.CarId Is Null THEN C.Mileage
      ELSE C.Mileage - P.Mileage
   END As Delta
FROM
   cteData As C
   LEFT JOIN cteData As P
   ON P.CarId = C.CarId
   And P.RowNumber = C.RowNumber - 1
ORDER BY
   C.CarId,
   C.Date
;

SQL フィドル

注:これは、「(3, 2/1/2000) のデータポイントが欠落している」ということは、2000 年 2 月の車 3 のテーブルに行がないことを意味すると想定しています。

于 2013-02-12T19:52:28.943 に答える
1

@Richard Deeming からのものと同じアプローチですが、これは可能な null 値を元の質問に含まれていると見なします。

;with cte ( rn, id, date, mileage )
as
(
  select
     row_number() over ( partition by id order by id, date )
     , id
     , date
     , mileage
   from
      cars
   where
      mileage is not null
)
select
  "current".id
  , "current".date
  , delta = isnull( "current".mileage - predecessor.mileage, "current".mileage )
from
  cte as "current"
  left join cte as predecessor
    on "current".id = predecessor.id
    and "current".rn - 1 = predecessor.rn

SQL-Fiddleを参照してください。

于 2013-02-12T22:48:02.317 に答える
1

ウィンドウ関数は素晴らしいです。しかし、SQL Server には、SQL Server 2012 まで必要なものがありません。そこでは、ラグ関数があります。

select t.*,
       (Milage - lag(Milage) over (partition by carId order by date)) as Delta
from t

以前のバージョンでは、相関サブクエリを使用できます。

[クエリのアップロードで問題が発生しました] 残念ながら。

    select t.*, (Mileage - prevMileage) as Delta
    from (select t.*,     
                 (select top 1 Mileage    from t t2
                  where t2.carId = t.carId and t2.date < t.date order by desc
                ) as prevDelta 
      from t
     ) t
于 2013-02-12T20:04:25.087 に答える
1

2012 関数、カーソル、while ループなどに依存せずにこれを実行しようとしています。

これは、いくつかの制限内で機能します。つまり、car#3 のエントリの null エントリが問題になります。

DECLARE @cars table ([id] int, [date] smalldatetime, [mileage] int)
INSERT INTO @cars ([id], [date], [mileage])
SELECT 1, '1/1/2000', 10000 UNION ALL
SELECT 1, '2/1/2000', 11000 UNION ALL
SELECT 1, '3/1/2000', 12000 UNION ALL
SELECT 2, '1/1/2000', 10000 UNION ALL
SELECT 2, '2/1/2000', 11000 UNION ALL
SELECT 2, '3/1/2000', 12000 UNION ALL
SELECT 3, '1/1/2000', 10000 UNION ALL
SELECT 3, '2/1/2000', NULL UNION ALL
SELECT 3, '3/1/2000', 12000


SELECT t1.id, t1.date, t1.mileage, t2.id, t2.date, t2.mileage, t1.mileage - t2.mileage as miles FROM @cars t1
LEFT JOIN @cars t2
ON t1.id = t2.id
AND t1.date = DATEADD(MONTH,1, t2.date)
于 2013-02-12T20:54:30.347 に答える