如何保持数据不排序?

时间:2013-07-20 10:40:26

标签: sql postgresql

我有一张表A:

Col1 Col2
12    a
12    c
12    b

如果我编码:Select * from A; 结果是:

Col1 Col2
12    a
12    b
12    d

我想获取数据是:

Col1 Col2
12    a
12    c
12    b

如何获取数据?

enter image description here

3 个答案:

答案 0 :(得分:3)

要理解的关键是SQL表没有排序。当SELECT没有ORDER BY时,您看到的行的顺序保持不变,因为数据库按顺序获取它们比其他顺序更快。当您对表执行顺序扫描时,PostgreSQL将仅按此顺序返回行;如果它可以使用查询的索引,那么通常会以其他顺序获取行。

您可能会发现this answer I wrote earlier信息丰富。

在PostgreSQL中,UPDATE到行可以将它们移动到表中的不同位置,从而改变它们返回的顺序。后台autovacuum进程和各种其他操作如VACUUM也可以和CLUSTER

所以你必须从不依赖于“默认”排序。如果您想为行提供某种顺序,他们必须有一个您可以对其进行排序的键。

如果您创建了一个没有密钥的表,现在意识到它应该有一个,您可以使用ctid系统列从这种情况中恢复。 依赖于此用于生产用途,它是一个系统内部列,用户只能看到紧急恢复和诊断目的。首先,查看物理磁盘排序是否实际上是您想要的顺序:

SELECT row_number() OVER () AS mytable_id, *
FROM mytable
ORDER BY ctid;

如果是,则可以添加一个新的键列,该键预先设置为以磁盘行顺序应用的自动递增键。有两种方法可以做到这一点。最安全的是:

BEGIN;
LOCK TABLE mytable IN ACCESS EXCLUSIVE MODE;
ALTER TABLE mytable RENAME TO mytable_old;

CREATE TABLE mytable (id SERIAL PRIMARY KEY, LIKE mytable_old INCLUDING ALL);

INSERT INTO mytable
SELECT row_number() OVER () AS id, *
FROM mytable_old
ORDER BY ctid;

SELECT setval('mytable_id_seq', (SELECT max(id)+1 FROM mytable));

COMMIT;

然后,如果您确定自己对结果感到满意,DROP TABLE mytable_old;。请参阅此演示:http://sqlfiddle.com/#!12/2cb99/2

快速简单但不太安全的方法是创建列并依赖PostgreSQL从头到尾重写表:

ALTER TABLE mytable ADD COLUMN mytable_id SERIAL PRIMARY KEY;

绝对没有保证 PostgreSQL将按顺序分配ID,但实际上它会这样做。请参阅this SQLFiddle demo

请注意,当您使用SEQUENCESERIAL列创建的内容)时,您可能会发现一些行为。当您一次插入多行时,行可能不一定按照您期望的顺序获得分配的ID,并且它们可能以与分配ID的顺序不同的顺序“显示”(变为可见)并插入此外,如果事务回滚,生成的ID将永远丢弃,因此您在编号中会出现空白。如果您希望数据库速度很快,这是非常好的,但如果您想要无间隙编号,这并不理想。如果这就是您所需要的,请搜索“postgresql gapless sequence”。

答案 1 :(得分:2)

要添加Craig Ringer给出的非常全面的答案,您可能需要考虑重新构建问题:为什么您希望行以特定顺序显示?很明显,这个命令有一些特殊的含义,“它们碰巧按顺序插入”是让数据库的技术性引领应用程序,而不是相反。

例如,可能是这些行代表某种事件,并且您希望按事件发生的顺序检索它们。在这种情况下,适当的排序列将是时间戳;就像一个自动增量序列一样,你可以给它一个默认值,当插入行时(但是可以通过显式插入列来覆盖它,或者稍后更新值,如果需要):

ALTER TABLE some_table ADD COLUMN event_date TIMESTAMP NOT NULL DEFAULT ( NOW() );

或者,也许它实际上是基于将在UI上显示的显示标签,在这种情况下,您只需ORDER BY显示标签,确保数据库使用正确的{{1} }。

最后,也许这是一个完全随意的显示顺序,可以调整它以将常用或重要的项目放在菜单的顶部。在这种情况下,显示顺序本身就是被建模项目的属性,因此在表格中应该有自己的列。由于collation是一个SQL关键字,我经常将这些列称为order,因此我可以说order_hint而不必担心特别引用列名。

答案 2 :(得分:1)

a_horse_with_no_name在评论中给出正确的答案。这是为了解决如何添加自动增量列。

创建表格时,请使用以下内容:

create table A (
    Aid int not null auto_increment primary key,
    col1 int,
    col2 varchar(255)
)

当您插入其中时,明确列出列:

insert into A(col1, col2)
    select 12, 'A';

现在您拥有所需格式的数据,列Aid提供“插入顺序”。然后你可以这样做:

select col1, col2
from A
order by id;

以“插入顺序”返回数据。请注意,由于更新和删除,数据实际上可能与输入顺序不同地排列在页面上。但是,order by明确地重新排序数据。

能够看到插入顺序是我总是在所有表中使用自动递增主键的原因之一。