注意以下所有解決方案假定ItemOrder是唯一
編輯添加一個解決方案,更像是什麼OP正在嘗試,並且可能更容易移植到Sybase,這次是在Microsoft SQL Server 2008上。(請參閱下面的解決方案,使用Oracle的分析功能,如果可用,可能會更有效。)
首先選擇讓我們行選擇標準正確:
declare @MoveUpId int
set @MoveUpId = 4
select current_row.Id
, current_row.ItemOrder
, prior_row.id as PriorRowId
, prior_row.ItemOrder as PriorItemOrder
, next_row.id as NextRowId
, next_row.ItemOrder as NextItemOrder
from #Items current_row
left outer join #Items prior_row
on prior_row.ItemOrder = (select max(ItemOrder)
from #Items
where ItemOrder < current_row.ItemOrder)
left outer join #Items next_row
on next_row.ItemOrder = (select min(ItemOrder)
from #Items
where ItemOrder > current_row.ItemOrder)
where @MoveUpId in (current_row.id, next_row.id)
然後根據上面的更新:
update current_row
set ItemOrder = case
when current_row.Id = @MoveUpId then prior_row.ItemOrder
else next_row.ItemOrder end
from #Items current_row
left outer join #Items prior_row
on prior_row.ItemOrder = (select max(ItemOrder)
from #Items
where ItemOrder < current_row.ItemOrder)
left outer join #Items next_row
on next_row.ItemOrder = (select min(ItemOrder)
from #Items
where ItemOrder > current_row.ItemOrder)
where @MoveUpId in (current_row.id, next_row.id)
Id ItemOrder
1 1
2 2
3 20
4 5
5 100
6 4000
10 -1
20 -2
設置@MoveUpId
到20,然後重新運行上面的查詢結果:
Id ItemOrder
1 1
2 2
3 20
4 5
5 100
6 4000
10 -2
20 -1
但我認爲這個問題是不特定於該平臺。這個問題可能並不具體,但答案可能是。例如,使用Oracle,首先,一張桌子和一些測試數據:
create table Items (Id number(38) not null
, ItemOrder number);
insert into items values (1, 1);
insert into items values (2, 2);
insert into items values (3, 5);
insert into items values (4, 20);
insert into items values (5, 100);
insert into items values (6, 4000);
insert into items values (10, -1);
insert into items values (20, -2);
commit;
接下來創建一個返回只是我們要與他們的新值更新爲Order
該行的查詢。 (這點我叫ItemOrder,訂單是保留字,全部)在Oracle中,這是simpliest使用分析功能lag
和lead
:
select *
from (select Id
, ItemOrder
, lead(Id) over (order by Id) as LeadId
, lead(ItemOrder) over (order by Id) as LeadItemOrder
, lag(ItemOrder) over (order by Id) as LagItemOrder
from Items)
where 4 in (Id, LeadId)
order by Id;
ID ITEMORDER LEADID LEADITEMORDER LAGITEMORDER
---------- ---------- ---------- ------------- ------------
3 5 4 20 2
4 20 5 100 5
轉換到這update語句。但是上面的查詢將不會創建(在Oracle)的更新視圖,所以使用合併改爲:
merge into Items TRGT
using (select Id
, ItemOrder
, lead(Id) over (order by Id) as LeadId
, lead(ItemOrder) over (order by Id) as LeadItemOrder
, lag(ItemOrder) over (order by Id) as LagItemOrder
from Items) SRC
on (SRC.Id = TRGT.Id)
when matched then update
set ItemOrder = case TRGT.Id
when 4 then SRC.LagItemOrder
else SRC.LeadItemOrder end
where 4 in (SRC.Id, SRC.LeadId);
select * from Items order by Id;
ID ITEMORDER
---------- ----------
1 1
2 2
3 20
4 5
5 100
6 4000
10 -1
20 -2
不幸的是,我不相信滯後和鉛被廣泛實施。據我所知,Microsoft SQL Server尚未實現它們。沒有ASE的經驗,他們擁有很棒的體驗。
Row_number()更廣泛地實現。 Row_number()可以用來獲得沒有間隙的東西。 (ROW_NUMBER()被refered爲在Oracle的解析函數和SQL Server上的窗口函數)。首先查詢:
with t as (select Id
, ItemOrder
, row_number() over (order by Id) as RN
from Items)
select current_row.id
, current_row.ItemOrder
, next_row.Id as NextId
, next_row.ItemOrder NextItemOrder
, prior_row.ItemOrder PriorItemOrder
from t current_row
left outer join t next_row on next_row.RN = current_row.RN + 1
left outer join t prior_row on prior_row.RN = current_row.RN - 1
where 4 in (current_row.id, next_row.id);
ID ITEMORDER NEXTID NEXTITEMORDER PRIORITEMORDER
---------- ---------- ---------- ------------- --------------
3 5 4 20 2
4 20 5 100 5
做了更新,再次合併,而不是更新。 (甲骨文確實允許update ... from ... join ...
語法,一個可能能夠逃脫更新,而不是在其他平臺上的合併。)
merge into Items TRGT
using (with t as (select Id
, ItemOrder
, row_number() over (order by Id) as RN
from Items)
select current_row.id
, current_row.ItemOrder
, next_row.Id as NextId
, next_row.ItemOrder as NextItemOrder
, prior_row.ItemOrder as PriorItemOrder
from t current_row
left outer join t next_row on next_row.RN = current_row.RN + 1
left outer join t prior_row on prior_row.RN = current_row.RN - 1
where 4 in (current_row.id, next_row.id)) SRC
on (TRGT.Id = SRC.Id)
when matched then update
set ItemOrder = case
when TRGT.Id = 4 then SRC.PriorItemOrder
else SRC.NextItemOrder end;
select *
from Items
order by Id;
ID ITEMORDER
---------- ----------
1 1
2 2
3 20
4 5
5 100
6 4000
10 -1
20 -2
注意注意上面的解決方案將改寫的OrderItems空,如果反對的ID匹配第一行。
「ID」序列中是否有空洞?機會是肯定的,但如果沒有,請將連接標準更改爲'c2.ORDER = c.ORDER + 1'。 –
不幸的是,是的......實際上,我已經邏輯刪除了所有項目(一個從所有查詢中排除的標誌,簡單)和類別。 –