ПРИМЕЧАНИЕ Все приведенные ниже решения предполагают, что 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, Order - зарезервированное слово и все.) В Oracle проще всего использовать аналитические функции 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
Преобразуйте это в оператор обновления. Однако приведенный выше запрос не создаст обновляемое представление (в 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 () упоминается как аналитическая функция в 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
Выполнение обновления, снова с слиянием вместо обновления. (Oracle допускает синтаксис 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
ПРИМЕЧАНИЕ Обратите внимание, что в приведенных выше решениях будет записано значение NULL для OrderItems при совпадении с Id для первой строки.