Reputation: 109
I have a table that has two cols REC_NO (INT), and ORDER_NO (INT). Structured like below
REC_NO || ORDER_NO
1 || 1
2 || 2
3 || 3
There can any number of rows in the table what I need to do is rotate the ORDER_NO so that 1 becomes 3, 2 becomes 1, and 3 becomes 2. I have done this using a hard coded case statement, but need some help making it more flexible. See the code below for what I have that does work for the limited set like above:
UPDATE ROTATION_LIST SET ORDER_NUM =
CASE
WHEN ORDER_NUM = 1 THEN 3
WHEN ORDER_NUM = 2 THEN 1
WHEN ORDER_NUM = 3 THEN 2
END
This is not a homework assignment or brain teaser I have an actual need for this.
Upvotes: 2
Views: 300
Reputation: 52645
If your RDMS supports LAG you could use it like so
WITH new_order
AS (SELECT rec_no,
COALESCE(Lag(order_no) OVER ( ORDER BY order_no), --Previous value
Max(order_no) OVER ( ORDER BY order_no DESC)) --Max Value when no previous
NEW_ORDER_NO
FROM rotation_list)
UPDATE rotation_list
SET order_no = new_order.new_order_no
FROM rotation_list
INNER JOIN new_order
ON rotation_list.rec_no = new_order.rec_no
If your RDMS support ROW_NUMBER but not LAG() (looking at you sql 2008) you can do this
WITH cte
AS (SELECT rec_no,
order_no,
Row_number() OVER ( ORDER BY order_no) rn
FROM rotation_list),
new_order
AS (SELECT no.rec_no,
COALESCE(no_prev.order_no,
Max(no.order_no) OVER (partition BY NULL )) new_order_no
FROM cte no
LEFT JOIN cte no_prev
ON no.rn - 1 = no_prev.rn)
UPDATE rotation_list
SET order_no = new_order.new_order_no
FROM rotation_list
INNER JOIN new_order
ON rotation_list.rec_no = new_order.rec_no;
Upvotes: 2
Reputation: 9150
And yet another, with Oracle syntax. Change the +1
to the the amount of rotation desired:
SELECT t.REC_NO, t.ORDER_NO
from myTable t
CROSS JOIN (SELECT COUNT(*) AS recordCount FROM myTable) s
ORDER BY MOD(rownum + 1, s.recordCount)
Upvotes: 0
Reputation: 10908
UPDATE ROTATION_LIST
SET ORDER_NUM = 1 + ORDER_NUM % (SELECT MAX(ORDER_NUM) FROM ROTATION_LIST)
Upvotes: 0
Reputation: 11910
Is it that you want to set the value for row 1 to be the # of rows and all the other rows is simply one less than the current value? Seems like a couple of queries would be my suggestion. Update the row with the number - 1 first, and then fix the value for one by taking the count of the order numbers.
Alternatively, you could set the value for 1 to be the max order number + 1, and then run the query to decrement all the values by one to get it to the right spot.
Upvotes: 1