在不同日期(每月的第一天)给出一张汽车及其里程表读数表,如何编写TSQL(理想情况下,用作SQL Server视图)以返回“增量”值?
换句话说,我希望从Calculate a Running Total in SQL Server进行反向操作。
示例:
在这张桌子上:
CarId | Date | Mileage --------------------------- 1 1/1/2000 10000 1 2/1/2000 11000 1 3/1/2000 12000 2 1/1/2000 10000 2 2/1/2000 11001 2 3/1/2000 12001 3 1/1/2000 10000 (missing datapoint for (3, 2/1/2000)) 3 3/1/2000 12000
我们会返回类似的内容(细节/边缘情况很灵活):
CarId | Date | Delta --------------------------- 1 1/1/2000 10000 1 2/1/2000 1000 1 3/1/2000 1000 2 1/1/2000 10000 2 2/1/2000 1001 2 3/1/2000 1000 3 1/1/2000 10000 3 3/1/2000 2000
答案 0 :(得分: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
;
NB:这假定“缺少(3,2 / 1/2000)的数据点”表示2000年2月的汽车3表中没有行。
答案 1 :(得分: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
答案 2 :(得分:1)
尝试在不依赖于任何2012函数,游标,while循环等的情况下执行此操作
这可以在一些限制范围内运行 - 也就是说,汽车#3的入口空值是一个问题:
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)
答案 3 :(得分:1)
与@Richard Deeming的方法相同,但这个方法与原始问题中包含的可能的空值相关。
;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。