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
CodePudding user response:
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
CodePudding user response:
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)
;