Archive for August 12th, 2009
Oracle: updating rows with partitioned incremental value
Comments enabled. I *really* need your comment
From Stack Overflow:
I have a table with these example data:
id idx data 1 1 A 1 3 B 2 1 C 2 1 D 2 5 E I want:
id idx data 1 1 A 1 2 B 2 1 C 2 3 D 2 4 E Is there a way to renumber the
indexperidusing a single SQLUPDATE?Note that the order of items should be preserved (i. e. the item E should still be after the items C and D but the order of C and D doesn't really matter).
The goal is to be able to create a primary key over
idandindex.
If not for the id, the query would be very simple:
UPDATE t_update SET index = rownum
However, the query above does not take id into account.
To update the table using partitioned row numbers, we need to employ the window function ROW_NUMBER().
However, it's usable neither in the UPDATE query itself, nor in an inline view, and attempt to use it produces an error:
ORA-30483: window functions are not allowed here
To work around the, we should rewrite the UPDATE query as MERGE.
MERGE requires two rowsets (source and target) and they need to be joined on something.
We will use the table itself as a source They only field we can join on here is ROWID pseudocolumn.
Here's the query to do this:
MERGE INTO t_update u USING ( SELECT rowid AS rid, ROW_NUMBER() OVER (PARTITION BY id ORDER BY idx) AS rn FROM t_update ) ON (u.rowid = rid) WHEN MATCHED THEN UPDATE SET idx = rn
, and here's the result:
SELECT * FROM t_update
| ID | IDX | DATA |
|---|---|---|
| 1 | 1 | A |
| 1 | 2 | B |
| 2 | 1 | C |
| 2 | 2 | D |
| 2 | 3 | E |
Works fine.
Subscribe in a reader