Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Oracle: Updating a table column using ROWNUM in conjunction with ORDER BY clause

I want to populate a table column with a running integer number, so I'm thinking of using ROWNUM. However, I need to populate it based on the order of other columns, something like ORDER BY column1, column2. That is, unfortunately, not possible since Oracle does not accept the following statement:

UPDATE table_a SET sequence_column = rownum ORDER BY column1, column2;

Nor the following statement (an attempt to use WITH clause):

WITH tmp AS (SELECT * FROM table_a ORDER BY column1, column2)
UPDATE tmp SET sequence_column = rownum;

So how do I do it using an SQL statement and without resorting to cursor iteration method in PL/SQL?

like image 673
Lukman Avatar asked May 23 '11 07:05

Lukman


People also ask

Can we use Rownum in update query?

You cannot use the NAME column to sort! UPDATE (SELECT name, order_id FROM test1 ORDER BY order_id) SET order_id = ROWNUM; Does not produce the expecting result because the order by is not used.

Can we use ORDER BY in update statement Oracle?

Each matching row is updated once, even if it matches the conditions multiple times. For multiple-table syntax, ORDER BY and LIMIT cannot be used.

Can we use Rownum in having clause?

HAVING refers to properties of groups created by GROUP BY , not to individual rows. You can't use ROWNUM in HAVING any more than you can use BYTES , or any other expression that may have different values for rows within a single group.

Can we use Rownum in WHERE clause in Oracle?

You can use ROWNUM to limit the number of rows returned by a query, as in this example: SELECT * FROM employees WHERE ROWNUM < 10; If an ORDER BY clause follows ROWNUM in the same query, then the rows will be reordered by the ORDER BY clause. The results can vary depending on the way the rows are accessed.


2 Answers

This should work (works for me)

update table_a outer 
set sequence_column = (
    select rnum from (

           -- evaluate row_number() for all rows ordered by your columns
           -- BEFORE updating those values into table_a
           select id, row_number() over (order by column1, column2) rnum  
           from table_a) inner 

    -- join on the primary key to be sure you'll only get one value
    -- for rnum
    where inner.id = outer.id);

OR you use the MERGE statement. Something like this.

merge into table_a u
using (
  select id, row_number() over (order by column1, column2) rnum 
  from table_a
) s
on (u.id = s.id)
when matched then update set u.sequence_column = s.rnum
like image 156
Lukas Eder Avatar answered Oct 06 '22 18:10

Lukas Eder


 UPDATE table_a
     SET sequence_column = (select rn 
                             from (
                                select rowid, 
                                      row_number() over (order by col1, col2)
                                from table_a
                            ) x
                            where x.rowid = table_a.rowid)

But that won't be very fast and as Damien pointed out, you have to re-run this statement each time you change data in that table.

like image 23
a_horse_with_no_name Avatar answered Oct 06 '22 19:10

a_horse_with_no_name