如何在SQL中表示并插入有序列表?

时间:2010-05-30 21:47:03

标签: sql sqlite

我想在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来按顺序获取所有元素。

4 个答案:

答案 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,goodbyehello相关联,现在必须链接到hey

但我不知道,是否有可能为许多数据库实现找到'order by'机制。

答案 2 :(得分:1)

您可以通过使用级联触发器轻松实现此目的,该触发器将插入/更新操作中等于新索引的任何“索引”条目更新为索引值+1。这将级联所有行,直到第一个间隙停止级联 - 请参阅this blog entry中的第二个示例以了解PostgreSQL实现。

这种方法应该独立于所使用的RDBMS,只要它支持在更新/插入之前触发的触发器。如果您在代码中实现了所需的行为(在遇到差距之前增加所有后续索引值),它基本上会执行您所做的操作,但是以更简单,更有效的方式。

或者,如果您可以接受对SQL Server的限制,请检查hierarchyid type。虽然主要用于定义嵌套层次结构,但您也可以将它用于平面排序。它有点类似于使用浮点数的方法,因为它允许通过分配小数值在两个位置之间插入,从而避免更新其他条目。

答案 3 :(得分:0)

我试图在这篇文章中回答一个类似的问题:Reordering an Ordered List。我希望它有所帮助。