计算TSQL中的去累积值?
给定每个月的第一天不同日期的汽车及其里程表读数表,理想情况下,如何编写TSQL作为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计算TSQL中的去累积值?,sql,tsql,Sql,Tsql,给定每个月的第一天不同日期的汽车及其里程表读数表,理想情况下,如何编写TSQL作为SQL Server视图来返回增量值 换言之,我希望从中执行反向操作 例如: 在这张桌子上: CarId | Date | Mileage --------------------------- 1 1/1/2000 10000 1 2/1/2000 11000 1 3/1/2000 12000 2 1/1/2000 1000
这适用于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
;
注意:假设2000年2月3日的数据点缺失,则表示2000年2月3日的车辆表中没有行。这适用于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
;
注意:假设2000年2月3日的数据点缺失,则表示2000年2月3日的车辆表中没有行。车窗功能非常好。但是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
窗口功能很棒。但是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
尝试在不依赖任何函数、游标、while循环等的情况下执行此操作 这在某些限制范围内工作-即,car3条目的空条目是一个问题:
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)
尝试在不依赖任何函数、游标、while循环等的情况下执行此操作 这在某些限制范围内工作-即,car3条目的空条目是一个问题:
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)
与@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
请参阅。与@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
看。我道歉。每次我试图更好地格式化该查询时,StackOverflow都会给我一个错误。我道歉。每次我试图更好地格式化查询时,StackOverflow都会给我一个错误。@Nico:真的吗?我刚刚试过,我觉得还可以:这取决于基础数据。我通过插入查询(见下文)对tamago提供的数据进行了查询。如果存在空值,则查询不会返回正确的结果,或者可能不是估计的结果;-若基础数据中根本并没有行,查询运行正常@尼科:真的吗?我刚刚试过,我觉得还可以:这取决于基础数据。我通过插入查询(见下文)对tamago提供的数据进行了查询。如果存在空值,则查询不会返回正确的结果,或者可能不是估计的结果;-若基础数据中根本并没有行,查询运行正常!我假设缺少数据点意味着表中没有一行,不是有一行,而是里程数为空。可能是一种观点。正如您在回答中所评论的,我参考了其他答案之一中的基本数据插入。特别是在我的情况下,我们确实有应该忽略的空记录。我假设缺少数据点意味着表中没有一行,不是有一行,而是里程数为空。可能是一种观点。正如您在回答中所评论的,我提到了在另一个回答中看到的基本数据插入。特别是在我的例子中,我们确实有应该忽略的空记录。