Reputation: 137
I have table with attribute change history, that looks like:
| id | attr | value | version |
|--------|----------|--------|---------|
| UUID-1 | name | chuck | 1 |
| UUID-1 | password | morris | 1 |
| UUID-1 | name | chack | 0 |
| UUID-2 | name | aron | 2 |
| UUID-2 | name | alan | 1 |
| UUID-2 | name | agor | 0 |
Now I have to drop old data for every 'id' (rows with MAX(version) should stay), and I want to get:
| id | attr | value | version |
|--------|----------|--------|---------|
| UUID-1 | name | chuck | 1 |
| UUID-1 | password | morris | 1 |
| UUID-2 | name | aron | 2 |
So, I've decided that i can obtain this with such construction:
DELETE
FROM
table1 pch
WHERE
EXISTS (
SELECT
id, MAX(version) AS maxVer
FROM
table1 pch2
WHERE
pch.id = pch2.id AND pch.version != maxVer
GROUP BY
id)
or something like this, but... oracle sql can't work with aliases in 'where/having' clauses.
any options to do this thing another way?
Upvotes: 0
Views: 842
Reputation: 15991
The one I always use is:
delete table1 t1
where t1.rowid in
( select lag(rowid) over (partition by id, attr order by version)
from table1 );
This deletes every previous row in order of version, partitioned by ID and ATTR.
UUID-1 has two rows with version = 1. I have retained the max row per ID + ATTR combination to match your expected results.
Upvotes: 0
Reputation: 1269445
Just use a correlated subquery instead of group by
:
DELETE FROM table1 pch
WHERE pch.version < (SELECT MAX(version) AS maxVer
FROM table1 pch2
WHERE pch.id = pch2.id
);
Upvotes: 1
Reputation: 4799
Here's a possible solution.
delete from history where rowid in
(select history.rowid from history join
(select ID, ATTR, max(version) version from history group by ID, ATTR) t
on history.ID = t.ID and history.ATTR = t.ATTR and history.VERSION <> t.version);
First, we find rows with max versions that should not be deleted.
Then we select rowids of those rows that have the same ID
and ATTR
, but different VERSION
(the 'old' rows).
And finally we remove those rows by rowids.
Upvotes: 0
Reputation: 8655
There are a lot of different variants... Just one of them:
delete from t
where
t.rowid in
(
select v.rowid
from (select
t1.rowid,
row_number()over(partition by t1.id,t1.attr order by version desc) rn
from t t1
) v
where rn>1
);
Upvotes: 0