SQL保留顺序

时间:2015-04-28 10:01:21

标签: sql postgresql sql-order-by

我有一个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子句以有序的方式检索数据。

我一直想知道是否存在可扩展且优雅的解决方案,可能涉及两个不需要重新分配订单索引的列。或者是否有某种最佳实践来解决这个问题?

4 个答案:

答案 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;