我有一个SQL表(PostgreSQL 9.3),基本上有一个ID列和一个值列(例如varchar)。我需要能够重现输入行的顺序。最天真的方法是依靠ID列的AUTOINCREMENT功能或者有一个特定的列进行排序,让我们说
CREATE TABLE "foo" (
"foo_id" SERIAL,
"order_index" int NOT NULL,
"value" VARCHAR(128)
);
数据可能看起来像
347 1 'foo'
368 2 'bar'
511 3 'baz'
我可以使用ORDER BY" order_index"来检索它们。子句。
问题是必须有可能在稍后的特定位置插入另一行,例如,当一排被意外遗漏时。在上面的解决方案中,我将不得不重新分配插入位置之后的所有order_index值。这不能很好地扩展,并且与优雅相反。
一种解决方案是在初始分配中留下空白,因此上面的示例看起来像
347 1000 'foo'
368 2000 'bar'
511 3000 'baz'
可以插入行直到填充间隙。只有这样才能进行重新分配。这是我迄今为止最好的主意。我还考虑了一个基于链表的想法的解决方案,其中每一行都有一列" successor_id"。但是,在这种情况下,我无法使用简单的ORDER BY子句以有序的方式检索数据。
我一直想知道是否存在可扩展且优雅的解决方案,可能涉及两个不需要重新分配订单索引的列。或者是否有某种最佳实践来解决这个问题?
答案 0 :(得分:0)
您的“差距”理念的变体:使用辅助排序列。
自行增加您的订单栏(不要使用AUTOINCREMENT),但将其视为自动增量列,仅增加+1(不是按照您的建议间隔增加)。然后,只需添加第二列,默认为0.在这两列上排序。
当您遇到插入缺失行的情况时,插入主ID列与其前面的行匹配,并在辅助排序列中插入“1”(或2,或3)。
但它会破坏您的ID列的唯一性。
答案 1 :(得分:0)
我有点担心您要将行重新插入已分配的序列号。更好的方法是使用timestamp
列来标识插入行的时间。您还可以创建history table
并在table
上添加触发器,以记录一行(insert, delete, update)
内的每个更改。这样,您可以在必要时重新创建行
<强>解决方案:强>
添加一列add_date timestamp NOT NULL DEFAULT NOW()
,这应该是最优雅的技巧(我相信)。
删除并插入id = 368
347 'foo' 2015-04-26 12:16:00
368 'bar' 2015-04-27 13:55:23
511 'baz' 2015-04-28 10:01:00
使用相同的序列号再次插入后
347 'foo' 2015-04-26 12:16:00
368 'bar' 2015-04-28 12:17:11
511 'baz' 2015-04-28 10:01:00
答案 2 :(得分:0)
使Class A {
public:
void foo(size_t id) {
tasks.remove_if(&A::IsEqual(id)); //Here I have an error
}
private:
std::list<Task> tasks;
struct IsEqual {
IsEqual(const Task& value) : _value(value) {}
bool operator() (const size_t id) {
return (_value._id == id);
}
Task _value;
};
};
成为一个浮点数,甚至更好numeric。
order_index
选择最适合您需要的精度和比例的值。
答案 3 :(得分:0)
用户输入(工作表的)数据。当他们查找数据时,他们可能希望在其他数据行之间插入另一个数据行。
所以他们总是在整个桌子的一小部分工作。那么重新编号记录并不是一件大事。我们假设您有一张表单,表明他们正在处理的工作表和每个工作表编号的订单索引。那么dbms处理这个问题并不是一件大事:
update sheets set order_index = order_index + 1
where sheet_no = 1234 and order_index >= 23;
insert into sheets (order_index, ...) values (23, new data);
commit;
我甚至会删除行并重新插入它们。
delete from sheets where sheet_no = 1234;
insert into sheets ...
...
commit;