Ajay
Ajay

Reputation: 6590

SQL Server reorder sequence number when records are moved up or down

I have one table in SQL Server with Id, Plan_Id, sequence_no and the following data.

Id          Plan_Id      sequence_no
----------- ------------ -----------
1132507748  1167096719   0
1102670655  1167096719   1
1166210290  1167096719   2

so on web site I am listing these records based on sequence_no. User can sort these records using drag & drop.

What I want here is, when user drag 1th record to 0th position then I want to reorder all records in table. I have Id,Plan_id and new sequence_no as parameter to procedure. I tried below code but it won't worked.

update dbo.planRecords
set sequence_no = sequence_no+1
where plan_id = @plan_id and sequence_no >= @newPosition

How can I reorder these records ?

Upvotes: 0

Views: 3299

Answers (2)

Salman Arshad
Salman Arshad

Reputation: 272106

You need to know the old position before you can move items around. And your logic needs to be different depending on whether the item was moved up or down. Rough outline of the process (not tested) is as follows:

DECLARE @Id INT = 1100000004; -- this id
DECLARE @NewPosition INT = 1; -- needs to have this position

WITH RowToMove AS (
    -- using cte instead of variables
    SELECT Plan_Id, sequence_no AS OldPosition
    FROM planRecords
    WHERE Id = @Id
), RowsToUpdate AS (
    -- columns used inside set and where clause of the update statement
    SELECT Id, sequence_no, OldPosition
    FROM planRecords
    CROSS JOIN RowToMove
    -- select rows that belong to same category and position between old and new
    WHERE planRecords.Plan_Id = RowToMove.Plan_Id AND sequence_no BETWEEN 
        CASE WHEN OldPosition < @NewPosition THEN OldPosition ELSE @NewPosition END AND
        CASE WHEN OldPosition > @NewPosition THEN OldPosition ELSE @NewPosition END
)
UPDATE RowsToUpdate SET sequence_no = CASE
    WHEN Id = @Id THEN @NewPosition -- this is the row we are moving
    WHEN OldPosition < @NewPosition THEN sequence_no - 1 -- row was moved down, move other rows up
    WHEN OldPosition > @NewPosition THEN sequence_no + 1 -- row was moved up, move other rows down
END;

Demo on DBFiddle using variables, using CTE

Upvotes: 3

Zohar Peled
Zohar Peled

Reputation: 82474

The simplest solution is to not use int, but decimal. That way, you only need to know the two closest siblings of the record, and only need to change the value of the sequence_no to a number between them.

For instance, if you have the following records in your database:

Id          Plan_Id      sequance_no
----------- ------------ -----------
1132507748  1167096719   1.0
1102670655  1167096719   2.0
1166210290  1167096719   3.0
1132507763  1167096719   4.0
1102670623  1167096719   5.0
1166210299  1167096719   6.0

and you want to move record 5.0 to between 1.0 and 2.0, all you need to do is to update it's sequence_no to 1.5:

Id          Plan_Id      sequance_no
----------- ------------ -----------
1132507748  1167096719   1.0
1102670623  1167096719   1.5
1102670655  1167096719   2.0
1166210290  1167096719   3.0
1132507763  1167096719   4.0
1166210299  1167096719   6.0

Decimal supports up to 38 digits so you can use up to 37 digits to the right of the decimal point, so even if you have a lot of changes in the order of the records, I'm pretty sure you will not have to worry about running out of slots.

If you want to display the order of the records in round numbers, you can always use row_number() over(order by sequence_no) to get a nice int values display.

Upvotes: 2

Related Questions