计算TSQL中的去累积值?

计算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

给定每个月的第一天不同日期的汽车及其里程表读数表,理想情况下,如何编写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
这适用于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提供的数据进行了查询。如果存在空值,则查询不会返回正确的结果,或者可能不是估计的结果;-若基础数据中根本并没有行,查询运行正常!我假设缺少数据点意味着表中没有一行,不是有一行,而是里程数为空。可能是一种观点。正如您在回答中所评论的,我参考了其他答案之一中的基本数据插入。特别是在我的情况下,我们确实有应该忽略的空记录。我假设缺少数据点意味着表中没有一行,不是有一行,而是里程数为空。可能是一种观点。正如您在回答中所评论的,我提到了在另一个回答中看到的基本数据插入。特别是在我的例子中,我们确实有应该忽略的空记录。