Sql: Retrieve Only the Records Whose Value Has Changed

SQL: retrieve only the records whose value has changed

If I read this right, you aren't looking for modified rows, but rows where the rate changes from the previous date. This query or something like it should do it:

SELECT  r1.Code, r1.Date, r1.Rate
FROM RateTable r1
WHERE r1.Rate <> (SELECT TOP 1 Rate
FROM RateTable
WHERE Date < r1.Date
ORDER BY Date DESC)

Select rows where column value has changed

I think this is what you're after:

;WITH x AS
(
SELECT value, time, rn = ROW_NUMBER() OVER
(PARTITION BY Value ORDER BY Time)
FROM dbo.table
)
SELECT * FROM x WHERE rn = 1;

This may be slow if the resultset is large and there isn't a good supporting index...

EDIT

Ah, wait a second, the values go up and down, not just up... if that is the case you can try this much slower approach:

DECLARE @x TABLE(value INT, [time] DATETIME)

INSERT @x VALUES
(0,'20120615 8:03:43 PM'),--
(1,'20120615 8:03:43 PM'),--*
(1,'20120615 8:03:48 PM'),--
(1,'20120615 8:03:53 PM'),--
(1,'20120615 8:03:58 PM'),--
(2,'20120615 8:04:03 PM'),--*
(2,'20120615 8:04:08 PM'),--
(3,'20120615 8:04:13 PM'),--*
(3,'20120615 8:04:18 PM'),--
(3,'20120615 8:04:23 PM'),--
(2,'20120615 8:04:28 PM'),--*
(2,'20120615 8:04:33 PM');

;WITH x AS
(
SELECT *, rn = ROW_NUMBER() OVER (ORDER BY time)
FROM @x
)
SELECT x.value, x.[time]
FROM x LEFT OUTER JOIN x AS y
ON x.rn = y.rn + 1
AND x.value <> y.value
WHERE y.value IS NOT NULL;

Results:

value  time
----- -----------------------
1 2012-06-15 20:03:43.000
2 2012-06-15 20:04:03.000
3 2012-06-15 20:04:13.000
2 2012-06-15 20:04:28.000

SQL: selecting rows where column value changed from previous row

SELECT a.*
FROM tableX AS a
WHERE a.StatusA <>
( SELECT b.StatusA
FROM tableX AS b
WHERE a.System = b.System
AND a.Timestamp > b.Timestamp
ORDER BY b.Timestamp DESC
LIMIT 1
)

But you can try this as well (with an index on (System,Timestamp):

SELECT System, Timestamp, StatusA, StatusB
FROM
( SELECT (@statusPre <> statusA AND @systemPre=System) AS statusChanged
, System, Timestamp, StatusA, StatusB
, @statusPre := StatusA
, @systemPre := System
FROM tableX
, (SELECT @statusPre:=NULL, @systemPre:=NULL) AS d
ORDER BY System
, Timestamp
) AS good
WHERE statusChanged ;

Select only the rows where a value changes

You could use LAG() window function in a later than your version of SQL Server, but without it you can use a correlated subquery in the WHERE clause:

SELECT t1.*
FROM tablename t1
WHERE t1.Amount <> COALESCE(
(
SELECT TOP 1 t2.Amount
FROM tablename t2
WHERE t2.CustomerId = t1.CustomerId AND t2.DateInvoice < t1.DateInvoice
ORDER BY t2.DateInvoice DESC
), -1)

See the demo.

Results:





























































CustomerIdInvoiceIdDateInvoiceAmount
20997257722020-12-109.50
20997257732021-01-151.50
20997257742021-01-172.50
20997257752021-01-193.50
20997257772021-01-239.50
20997257792021-01-253.50
21097261322021-02-023.50
21097261332021-03-029.50

return row where column value changed from last change

use lag() to find the last change (order by RecordAddedDate desc) in PartNumberID.

cumulative sum sum(isChange) to group the related rows under same group no. grp = 0 with be the rows of the last change

To get the min - RecordAddedDate, use row_number()

with 
cte1 as
(
select *,
isChange = case when PartNumberID
= isnull(lag(PartNumberID) over (partition by Location
order by RecordAddedDate desc),
PartNumberID)
then 0
else 1
end
from mytable
),
cte2 as
(
select *, grp = sum(isChange) over (partition by Location order by RecordAddedDate desc)
from cte1
),
cte3 as
(
select *, rn = row_number() over (partition by Location order by RecordAddedDate)
from cte2 t
where t.grp = 0
)
select *
from cte3 t
where t.rn = 1

db<>fiddle demo

SQL Return last record where column value changed and amount of change

First with a CTE which returns all the changes and then with NOT EXISTS that returns the last change for each Entity:

(Edited with the actual table and column names)

with cte as (
select t.hUnit UnitID, (t.cRent - tt.cRent) cRentChange, t.dtDate DateofChange
from unit_history t inner join unit_history tt
on
tt.hUnit = t.hUnit
and
tt.dtDate = (
select max(dtDate)
from unit_history
where hUnit = t.hUnit and dtDate < t.dtDate
)
where t.cRent <> tt.cRent
)

select c.* from cte c
where not exists (
select 1 from cte
where UnitID = c.UnitID and DateofChange > c.DateofChange
)

See the demo.

Results:

 Entity | ValueChange | DateofChange       
> :----- | ----------: | :------------------
> A | 100 | 01/01/2018 00:00:00
> B | 150 | 01/01/2019 00:00:00

Selecting rows where a value has changed

select p1.date_entered, 
p1.WholeSale,
p1.Volume,
p1.Clearance
FROM pricetable p1
CROSS APPLY
--cross apply to most recent prior record
(SELECT TOP 1 *
FROM pricetable p2
where p1.product = p2.product
and p2.date_entered < p1.date_entered
order by p2.date_entered desc) CA
where p1.product = 'TANGO'
and (p1.wholesale != CA.wholesale or p1.volume != CA.volume or p1.clearence != CA.clearence)
order by p1.date_entered desc

SQL How to retrieve first row when value changed?

I understand that you want the first 1 - for series that start with 0 only.

If you are running MySQL 8.0, you can use window functions for this:

select id, min_date
from (
select
id,
flag,
row_number() over(partition by id order by date) rn,
min(case when flag = 1 then date end) over(partition by id) min_date
from mytable
) t
where rn = 1 and flag = 0

The subquery ranks records having the same id by date and computes the date of the first 1 flag in the group; thie outer query filters on the first record per group, ensures that it has a 0 flag, and displays the computed date.

Select rows where value changed in column

In SQL Server 2012+, you would use lead():

select t.*
from (select t.*,
lead(charge_code) over (partition by account order by postingdate) as next_charge_code
from t
) t
where charge_code <> next_charge_code;

In earlier versions of SQL Server, you can do something similar with apply.



Related Topics



Leave a reply



Submit