先考虑按SortId降序排列的情况。初始状态SortId=Id
方案1,首先获取当前最大的SortId,例如:@MaxSid = 100
其次,将要置顶的行重新升序排列放入表变量里,并添加一列序号列
select row_number() over(order by sortid) as NId,Id,SortId
from T_Test
where id in(11,22,33,44)
order by sortid
结果:
NId | Id | SortId |
1 | 11 | 11 |
2 | 22 | 22 |
3 | 33 | 33 |
4 | 44 | 44 |
然后,计算出新的SortId=@MaxSid+NId
declare @t table(nid int,id int)
insert into @t
select row_number() over(order by sortid) as NId,Id
from T_Test
where id in(11,22,33,44)
order by sortid
update T_Test set SortId = @MaxSid + b.nid
from T_Test as a
join @t as b on a.id=b.id
where a.id in(11,22,33,44)
结果:
NId | Id | SortId |
1 | 11 | 101 |
2 | 22 | 102 |
3 | 33 | 103 |
4 | 44 | 104 |
此方法,会导致SortId无限增加,有可能造成溢出
另外,有的情况可能有要求,必须使用现有的SortId。这就需要将最大的SortId赋给要置顶的目标。顶部和目标之间的项依次下降。
方案2,先针对单条数据的位置移动写一个存储过程
P_Swt(原始SortId,目标SortId)
然后取出所有要置顶的元素,遍历
调用 P_Swt(原始SortId,最大SortId递减)
代码先不写了,这个方法在逻辑上比较好理解,也好维护,有一定复用性,比较灵活,
但是比较浪费性能
每次遍历都需要将很多数据的SortId减一,很多数据会重复多次减一这个动作
方案3,将要置顶的数据中SortId最小也就是最底部的数据一直到全部数据中最大的SortId,之间的SortId分区。
这样,不同区间要下降的位移不同的,每个区间移动一次就可以了
例如:要置顶 11,22,33,44
可以写成:
update T_Test set SortId=SortId-1 where SortId>44 and SortId<=@MaxSid
update T_Test set SortId=SortId-2 where SortId>33 and SortId<44
update T_Test set SortId=SortId-3 where SortId>22 and SortId<33
update T_Test set SortId=SortId-4 where SortId>11 and SortId<22
然后,按照方案一移动目标数据就可以了
所以剩下的就是如何自动生成上边的脚本了
是不是只能遍历呢?
好像是的。
游标编列或是数组遍历都可以
数组方案:
http://blog.csdn.net/fuyouhu2008/article/details/5150625
唯一要注意的就是第一条脚本生成的时候需要处理一下,或者遍历之前直接将(@MaxSid+1)插入到要遍历的数据中
这样脚本模板比较好写了,从第二条可是遍历
update T_Test set SortId = SortId - i where SortId>@Current and SortId<@Prev
此方案需要较多逻辑处理,和方案一一样不利于维护。复用性不高。
结束。
Ps:既然必定要一次更新很多条数据,而且除了方案一都会对此更新,并发是不可避免的问题。
如何处理并发呢?
锁定表? 好像可以,但不利于用户体验
锁定置顶按钮? 也就是,置顶的时候如果堵塞,返回置顶失败,这样只有第一个可以置顶成功。