2013-02-12 159 views
1

給定一個汽車的表格和他們在不同日期(每月的第一個月)讀取里程錶的數據,我如何編寫TSQL(理想情況下,用作SQL Server視圖)以返回「增量」值?計算TSQL中的非累積值?

換句話說,我想從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 

回答

1

相同的方法,從@理查德明,但這一個考慮可能的空值包括在原來的問題。

;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

+0

我假設「缺少數據點」意味着表中沒有一行,不是有一行,但里程是「NULL」。 – 2013-02-13 12:01:50

+0

也許是一個觀點。正如您在答案中所評論的那樣,我提到了在其他解答之一中看到的基本數據插入。 – Nico 2013-02-13 12:14:49

+0

在我的情況下,特別是,我們確實有空值的記錄應該被忽略。 – 2013-02-25 15:52:42

2

這應該爲2005年的工作SQL或更高:

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 Fiddle

注:這是假定「丟失的數據點爲(3,2000年2月1日)」意味着在表3車排不出,2000年2月

+0

這個查詢實際上返回的是錯誤的結果3 – Nico 2013-02-12 22:44:29

+0

@Nico:真的嗎?我剛剛嘗試過,它對我來說看起來還不錯:http://www.sqlfiddle.com/#!3/d41d8/8780 – 2013-02-13 12:00:40

+0

它取決於基礎數據。我通過插入查詢對tamago提供的數據運行查詢(見下文)。如果存在NULL值,查詢不會返回正確的結果(或者可能不是估計的結果;)) - 如果基本數據中完全沒有行,則查詢運行正常! – Nico 2013-02-13 12:13:28

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 
+0

我很抱歉。每次我嘗試更好地格式化查詢時,StackOverflow都會給我一個錯誤。 – 2013-02-12 20:09:15

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)