This question has been asked previously and been well answered for MySQL specifically, however I'd very much appreciate your guys' help in translating this for SQL Server. The prior posts are closed and I didn't want to reopen them as they're quite old.
Below is the dataset to query, and the required output of the query solution. Below that is the excellent MySql solution posted here ( SQL best way to subtract a value of the previous row in the query? ). My question is how to accomplish the same result with variables in SQL Server. I apologize if this is a novice question, but I'm new to variables in SQL Server and have failed in my attempts to translate to SQL Server based on MSDN documentation on variables in SQL Server.
Thank you for your help!
select
EL.SN,
EL.Date,
EL.EL.Value,
if( @lastSN = EL.SN, EL.Value - @lastValue, 0000.00 ) as Consumption,
@lastSN := EL.SN,
@lastValue := EL.Value
from
EnergyLog EL,
( select @lastSN := 0,
@lastValue := 0 ) SQLVars
order by
EL.SN,
EL.Date
I need to have the consumption value base on previous one by SN number. This is my data:
TABLE EnergyLog
SN Date Value
2380 2012-10-30 00:15:51 21.01
2380 2012-10-31 00:31:03 22.04
2380 2012-11-01 00:16:02 22.65
2380 2012-11-02 00:15:32 23.11
20100 2012-10-30 00:15:38 35.21
20100 2012-10-31 00:15:48 37.07
20100 2012-11-01 00:15:49 38.17
20100 2012-11-02 00:15:19 38.97
20103 2012-10-30 10:27:34 57.98
20103 2012-10-31 12:24:42 60.83
This is the result I need:
SN Date Value consumption
2380 2012-10-30 00:15:51 21.01 0
2380 2012-10-31 00:31:03 22.04 1.03
2380 2012-11-01 00:16:02 22.65 0.61
2380 2012-11-02 00:15:32 23.11 0.46
20100 2012-10-30 00:15:38 35.21 0
20100 2012-10-31 00:15:48 37.07 1.86
20100 2012-11-01 00:15:49 38.17 1.1
20100 2012-11-02 00:15:19 38.97 0.8
20103 2012-10-30 10:27:34 57.98 0
20103 2012-10-31 12:24:42 60.83 2.85
By using a CTE you would be able to get the data ordered, and then select the previous record.
WITH PREVCTE AS (
SELECT *,
ROW_NUMBER() OVER (PARTITION BY SN ORDER BY MyDate) [RowNum]
FROM @myTable
)
SELECT A.SN,
A.MyDate,
A.[Value],
A.[Value] - COALESCE(B.[Value], A.[Value]) [Consumption]
FROM PREVCTE A LEFT OUTER JOIN PREVCTE B
ON A.RowNum - 1 = B.RowNum AND
A.SN = B.SN
My previous solution had calculated running totals. After shawnt00's comment and looking back at the example that you've provided I see that's not the case. This should make a solution much easier. I believe that the following will work for SQL 2008, although I don't have a 2008 box handy at the moment to test it.
;WITH CTE_Ordered AS
(
SELECT
sn,
[date],
value,
ROW_NUMBER() OVER(PARTITION BY sn ORDER BY [date]) AS row_num
FROM
dbo.EnergyLog
)
SELECT
T1.sn,
T1.[date],
T1.value,
T1.value - COALESCE(T2.value, 0) AS consumption
FROM
CTE_Ordered T1
LEFT OUTER JOIN CTE_Ordered T2 ON
T2.sn = T1.sn AND
T2.row_num = T1.row_num - 1
ORDER BY
T1.sn,
T1.row_num
I believe you're looking for the difference between adjacent dates. Here's one way.
select
SN, Date, Value,
Value - (
select coalesce(max(Value), 0) from EnergyLog el2
where el2.SN = el.SN and el2.Date < el.Date
group by el2.SN
) as consumption
from EnergyLog el
You might get a performance boost by narrowing the size of the look-back window if you can always assume the time between is capped. That's going to depending on indexing too.
select
SN, Date, Value,
Value - (
select coalesce(max(Value), 0) from EnergyLog el2
where el2.SN = el.SN
and el2.Date > dateadd(hour, -48, el.Date) /* max gap 48 hrs? */
and el2.Date < el.Date
group by el2.SN
) as consumption
from EnergyLog el
EDIT: Based on your comment below regarding sequence numbers:
select
SN, Date, Value,
Value - (
select coalesce(max(Value), 0) from EnergyLog el2
where el2.SN = el.SN and el2.SeqNo = el.SeqNo - 1
group by el2.SN
) as consumption
from EnergyLog el
You can certainly use an outer join rather than the scalar subquery. Of course if you already have a sequence number then you won't need row_number()
to generate them.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.