简体   繁体   中英

How modify sequence numbers based on one changed sequence number in oracle sql

How to change the rest sequence numbers when one sequence number changed. Then sort the rows based on sequence number. Here's the example:

  seq_nbr
A 1        |   A 1       |  A 1
B 2 -> 5   |   B 5       |  C 2
C 3        |   C 3 -> 2  |  D 3
D 4        |   D 4 -> 3  |  E 4
E 5        |   E 5 -> 4  |  B 5

You can use a MERGE statement with the ROW_NUMBER analytic function:

MERGE INTO table_name dst
USING (
  WITH new_seq_nbr (value, new_nbr) AS (
    SELECT 'B', 5 FROM DUAL                       -- Your change goes here.
  )
  SELECT t.ROWID AS rid,
         ROW_NUMBER() OVER (
           ORDER BY
             CASE t.value
             WHEN n.value
             THEN 2 * new_nbr + 1
             ELSE 2 * seq_nbr
             END
         ) AS new_seq_nbr
  FROM   table_name t
         CROSS JOIN new_seq_nbr n
) src
ON (src.rid = dst.ROWID)
WHEN MATCHED THEN
  UPDATE
  SET dst.seq_nbr = src.new_seq_nbr
  WHERE dst.seq_nbr <> src.new_seq_nbr;

Which, for the sample data:

CREATE TABLE table_name (value PRIMARY KEY, seq_nbr UNIQUE) AS
SELECT 'A', 1 FROM DUAL UNION ALL
SELECT 'B', 2 FROM DUAL UNION ALL
SELECT 'C', 3 FROM DUAL UNION ALL
SELECT 'D', 4 FROM DUAL UNION ALL
SELECT 'E', 5 FROM DUAL UNION ALL
SELECT 'F', 6 FROM DUAL;

After then MERGE then:

SELECT * FROM table_name ORDER BY seq_nbr;

Outputs:

VALUE SEQ_NBR
A 1
C 2
D 3
E 4
B 5
F 6

db<>fiddle here

When the new sequence number assigned to B is greater than the old one, the sequence numbers between the old and the new value are pushed down (subract 1), to keep the consecutive numbering in that column.

Sayan M asked you in a comment what the desired result is if you change the sequence number to a lower value rather than higher. Presumably in that case all the sequence numbers between the old and new value must be pushed up (add 1), to keep the consecutive numbering.

The update statement below addresses both cases (as well as the trivial case when the sequence number doesn't change - it's updated to itself). It does not require analytic functions and it works as an update statement.

I assume the same table and column names as in MT0's answer, and the inputs are a "value" and a "new sequential number" (such as "B" and "5") - given as bind variables.

update 
  (
    select value, seq_nbr,
           (select seq_nbr from table_name where value = :i_value) as old_nbr
    from   table_name
  )
  set seq_nbr = 
    case when value = :i_value then :i_nbr
         else seq_nbr + case when :i_nbr > old_nbr then -1 else 1 end
    end
  where :i_nbr != old_nbr 
    and seq_nbr between least(:i_nbr, old_nbr) and greatest(:i_nbr, old_nbr)
;

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM