我想在SQL表中表示“hi”,“hello”,“goodbye”,“good day”,“howdy”(带有该顺序)列表:
pk | i | val
------------
1 | 0 | hi
0 | 2 | hello
2 | 3 | goodbye
3 | 4 | good day
5 | 6 | howdy
'pk'是主键列。无视其价值观。
'i'是定义'val'列中值的顺序的“索引”。 仅用于建立订单,而值则不重要。
我遇到的问题是在维护订单的同时将值插入列表中。例如,如果我想插入“嘿”并且我希望它在“hello”和“goodbye”之间出现,那么我必须改变“再见”和“好”的“i”值一天“(但最好不是”你好“)为新条目腾出空间。
那么,是否有一个标准的SQL模式来进行移位操作,但只移位必要的元素? (注意,一个简单的“UPDATE表SET i = i + 1 WHERE i> = 3”不起作用,因为它违反了'i'上的唯一性约束,并且它也不必要地更新了“howdy”行。)
或者,有没有更好的方式来表示有序列表?我想你可以让'i'成为一个浮点值并选择两者之间的值,但是当没有这样的值时你必须有一个单独的重新平衡操作。
或者,是否有一些标准算法用于在任意其他字符串之间生成字符串值,如果我要使'i'为varchar?
或者我应该将其表示为链接列表?我正在避免这种情况,因为我还想能够做一个SELECT .. ORDER BY来按顺序获取所有元素。
答案 0 :(得分:5)
当我阅读你的帖子时,我一直在想'链表' 最后,我仍然认为这是要走的路。
如果您使用的是Oracle,并且链表是一个单独的表(甚至是具有自引用ID的同一个表 - 我会避免),那么您可以使用CONNECT BY查询和伪列LEVEL来确定排序顺序。
答案 1 :(得分:1)
如果您不使用数字,但使用字符串,则可能有一个表格:
pk | i | val
------------
1 | a0 | hi
0 | a2 | hello
2 | a3 | goodbye
3 | b | good day
5 | b1 | howdy
您可以在a3和b之间插入a4,在a2和a3之间插入a21,在a0和a2之间插入a1,依此类推。您需要一个聪明的功能,在p和n之间为新值v生成i,并且索引可以变得越来越长,或者您需要不时地进行大的重新平衡。
另一种方法可能是,在表中实现一个(双)链表,你不保存索引,但链接到上一个和下一个,这意味着你通常需要更新1-2要素:
pk | prev | val
------------
1 | 0 | hi
0 | 1 | hello
2 | 0 | goodbye
3 | 2 | good day
5 | 3 | howdy
你好,你好吗?再见:
嘿得到pk 6,
pk | prev | val
------------
1 | 0 | hi
0 | 1 | hello
6 | 0 | hi <- ins
2 | 6 | goodbye <- upd
3 | 2 | good day
5 | 3 | howdy
前一个元素为hello
,pk = 0,goodbye
与hello
相关联,现在必须链接到hey
。
但我不知道,是否有可能为许多数据库实现找到'order by'机制。
答案 2 :(得分:1)
您可以通过使用级联触发器轻松实现此目的,该触发器将插入/更新操作中等于新索引的任何“索引”条目更新为索引值+1。这将级联所有行,直到第一个间隙停止级联 - 请参阅this blog entry中的第二个示例以了解PostgreSQL实现。
这种方法应该独立于所使用的RDBMS,只要它支持在更新/插入之前触发的触发器。如果您在代码中实现了所需的行为(在遇到差距之前增加所有后续索引值),它基本上会执行您所做的操作,但是以更简单,更有效的方式。
或者,如果您可以接受对SQL Server的限制,请检查hierarchyid type。虽然主要用于定义嵌套层次结构,但您也可以将它用于平面排序。它有点类似于使用浮点数的方法,因为它允许通过分配小数值在两个位置之间插入,从而避免更新其他条目。
答案 3 :(得分:0)
我试图在这篇文章中回答一个类似的问题:Reordering an Ordered List。我希望它有所帮助。