我有一个包含复合主键的表:
table MyTable
(
some_id smallint not null,
order_seq smallint not null,
--other columns
)
...其中some_id
和order_seq
组成了一个复合主键。 order_seq
列用于确定C#3.5 / ASP.NET应用程序其他部分的显示顺序。
我正在设置一个管理页面,用户可以在其中随机播放这些行,一次更改多行'order_seq
值:
屏幕上的所有项目都具有相同的some_id
。当用户点击“提交”时,新的order_seq
值应该保存到数据库中。
我的问题是order_seq
是PK的一部分,所以改变这些东西的任务变得复杂。由于some_id
是相同的,我无法识别order_seq
本身以外的其他内容,这些内容随着我的变化而变化。此外,我必须确保order_seq
值保持唯一(可能具有某种临时值)。
我最好的想法是使用某种内存中的集合来跟踪我到目前为止所做的更改。但是,我在实施它时遇到了麻烦。如何一次对多行进行就地重新排序?我可以使用基于C#或SQL的解决方案。
编辑:不幸的是,我对表设计无法控制,并且对数据库的控制有限。我将无法更改PK方案或引入任何新列。
答案 0 :(得分:2)
如果可能的话,如果你引入一个代理主键,你将为自己节省很多压力。由于您可以在不更改任何其他字段的情况下更改order_seq,因此它并不适合作为主键的一部分(记录中的所有其他字段应直接依赖于该键)。但即使超出理论上的东西,你也已经发现了这种复合键的技术问题。
如果确实需要保持结构相同,那么更改关键字段将会很繁琐,而且正如您已经想到的那样,需要一些临时值。如果我不得不做到这一点,我将分两步完成:
UPDATE Table SET order_seq = @newval + BIG_OFFSET WHERE order_seq = @oldval
UPDATE Table SET order_seq = order_seq - BIG_OFFSET WHERE order_seq > BIG_OFFSET
显然,为每个不同的行运行第一个语句,然后在最后运行第二个语句来重置它们的值。这可以防止您在过程中的任何一点都有重复的主键。
答案 1 :(得分:1)
您需要存储原始复合PK(隐藏列)。在屏幕上,如果您正确管理,两个项目不应该具有相同的顺序。然后,您可以找到包含原始复合PK的项目,并使用新订单值更新它们。
编辑:好的,您可以在代码中执行类似的操作,即跟踪具有原始PK和当前PK的对象列表,任何时候用户尝试更改顺序,如果允许则执行验证,然后允许或阻止它。您需要找到具有更新的Id和orderId的对象,如果找到了,则不允许。 对不起,如果我不明白这个问题。试着帮忙。
答案 2 :(得分:1)
你可以使用带有一对旧的order_seq和新的order_seq的XML参数的SP来实现。
一些测试数据
create table MyTable
(
some_id int,
order_seq int,
name varchar(10)
primary key(some_id, order_seq)
)
insert into MyTable values
(1, 1, '1_1'),
(1, 2, '1_2'),
(1, 3, '1_3'),
(1, 4, '1_4'),
(2, 1, '2_1'),
(2, 2, '2_2')
存储过程
create procedure SetOrder
@some_id int,
@new_order xml
as
;with cte as
(
select
X.N.value('@OldSeq', 'int') as OldSeq,
X.N.value('@NewSeq', 'int') as NewSeq
from @new_order.nodes('/i') as X(N)
)
update T
set order_seq = C.NewSeq
from MyTable as T
inner join cte as C
on T.order_seq = C.OldSeq
where T.some_id = @some_id
要反转some_id = 1
调用SP的顺序,请执行以下操作:
exec SetOrder 1,
'<i OldSeq="1" NewSeq="4"/>
<i OldSeq="2" NewSeq="3"/>
<i OldSeq="3" NewSeq="2"/>
<i OldSeq="4" NewSeq="1"/>'
您需要在客户端上跟踪旧的order_seq,并在用户选择提交更改时构建xml。