主键列的就地重新排序

发布于 2024-11-04 21:01:16 字数 877 浏览 0 评论 0原文

我有一个带有复合主键的表:

table MyTable 
(
    some_id smallint not null,
    order_seq smallint not null,
    --other columns
)

...其中 some_idorder_seq 组成了复合主键。 order_seq 列用于确定 C# 3.5/ASP.NET 应用程序其他部分的显示顺序。

我正在设置一个管理页面,用户可以在其中随机排列这些行,一次更改多行的 order_seq 值:

screenshot

屏幕上的所有项目都具有相同的 some_id 当用户单击“提交”时,新的 order_seq 值将显示应该保存到数据库中。

我的问题是 order_seq 是 PK 的一部分,因此整理这些内容的任务变得很复杂。由于 some_id 是相同的,因此除了 order_seq 本身之外,我无法识别它们,因为它会随着我的操作而变化。此外,我必须确保 order_seq 值保持唯一(可能具有某种临时值)。

我最好的想法是使用某种内存中的集合来跟踪我迄今为止所做的更改。不过,我在实施它时遇到了麻烦。如何一次对多行进行就地重新排序?我可以使用基于 C# 或 SQL 的解决方案。

编辑:不幸的是,我对表设计的控制为零,对数据库的控制通常有限。我将无法更改 PK 方案或引入任何新列。

I have a table with a composite primary key:

table MyTable 
(
    some_id smallint not null,
    order_seq smallint not null,
    --other columns
)

...where some_id and order_seq make up a composite primary key. The order_seq column is used to determine the display order in other parts of my C# 3.5/ASP.NET application.

I'm setting up an admin page where users can shuffle these rows around, changing multiple rows' order_seq values at a time:

screenshot

All items on the screen have the same some_id. When the user clicks Submit, the new order_seq values are supposed to be saved to the database.

My problem is that order_seq is part of the PK, so the task of shuffling these things around becomes complicated. Since some_id is the same, I have no way of identifying them other than order_seq itself, which changes as I go. Furthermore, I have to make sure the order_seq values stay unique (presumably with some kind of temp value).

The best idea I have is to use some kind of in-memory collection to keep track of the changes I've made so far. I'm having trouble implementing it, though. How can I do an in-place resequence of multiple rows at once? I'd be fine with either a C# or SQL-based solution.

EDIT: Unfortunately, I have zero control over the table design, and limited control over the DB in general. I won't be able to change the PK scheme or introduce any new columns.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

℉服软 2024-11-11 21:01:16

如果可能的话,引入代理主键将为您减轻很多压力。由于您可以更改 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

显然,为每个正在更改的不同行运行第一个语句,然后在最后运行第二个语句以重置它们的值。这应该可以防止您在此过程中的任何时候出现重复的主键。

If at all possible, you will save yourself a lot of stress if you introduce a surrogate primary key. Since you can change the order_seq without changing any of the other fields, it's doesn't really fit as part of the primary key (which all other fields in your record should directly depend on). But even beyond the theoretical stuff, you're already discovering the technical problems with this kind of compound key.

If you do need to keep the structure the same, then changing the key fields is going to be tedious and, as you already figured out, require some temporary values. Off the top of my head, if I had to accomplish this I'd do it in two steps:

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

Obviously, run the first statement for every distinct row that's changing, then run the second statement at the very end to reset their values. This should prevent you from having duplicate primary keys at any point in the process.

云巢 2024-11-11 21:01:16

您需要存储原始复合 PK(隐藏列)。在屏幕上,如果管理得当,两个项目不应该具有相同的顺序。然后,您可以找到具有原始复合 PK 的商品,并使用新的订单值更新它们。

编辑:好吧,您可以在代码中执行类似的操作,即跟踪具有原始 PK 和当前 PK 的对象列表,任何时候用户尝试更改顺序,如果允许,则进行验证,然后允许或阻止它。您需要找到一个具有更新的 Id 和 orderId 的对象,如果您确实找到了一个对象,则不允许这样做。
抱歉,如果我没理解这个问题。试图提供帮助。

You'll need to store the original composite PK (hidden column). On the screen, if you manage it properly, two items should not have the same order. Then you can find the items with the original composite PK and update them with your new order values.

Edit: All right, you can do similar thing in your code, ie, keep track of the list of objects with original PK and current PK, any time user tries to change order, do a validation if it's allowed, and then either allow or block it. You'll need to find an object with updated Id and orderId, if you do find one, then it's not allowed.
Sorry, if I haven't understood the problem. Trying to help.

み青杉依旧 2024-11-11 21:01:16

您可以使用带有 XML 参数以及一对旧 order_seq 和新 order_seq 的 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 。

You can do it with a SP that takes a XML parameter with a pair of the old order_seq and the new order_seq.

Some test data

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')

Stored proc

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

To reverse the order for some_id = 1 call the SP like this:

exec SetOrder 1, 
  '<i OldSeq="1" NewSeq="4"/>
   <i OldSeq="2" NewSeq="3"/>
   <i OldSeq="3" NewSeq="2"/>
   <i OldSeq="4" NewSeq="1"/>'

You need to keep track of the old order_seq on the client and build the xml when the user chooses to submit the changes.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文