复合键的每组行的序列号

时间:2014-07-23 18:50:56

标签: sql postgresql database-design auto-increment

我正在尝试维护地址历史记录表:

CREATE TABLE address_history (
    person_id int, 
    sequence int,
    timestamp datetime default current_timestamp,
    address text,
    original_address text,
    previous_address text,
    PRIMARY KEY(person_id, sequence),
    FOREIGN KEY(person_id) REFERENCES people.id
);

我想知道是否有一种简单的方法可以自动编号/约束sequence address_history,以便自动从每个person_id的1开始计数。

换句话说,person_id = 1的第一行将获得sequence = 1; person_id = 1的第二行将获得sequence = 2person_id = 2的第一行会再次获得sequence = 1。等
另外,有更好的/内置的方式来维护这样的历史记录吗?

1 个答案:

答案 0 :(得分:15)

别。它经过多次尝试,很痛苦。

使用普通serial列:

CREATE TABLE address_history (
   address_history_id serial PRIMARY KEY
  ,person_id int NOT NULL REFERENCES people(id)
  ,created_at timestamp NOT NULL DEFAULT current_timestamp
  ,previous_address text
);

使用窗口函数row_number()获取序列号,每个person_id没有间隙。您可以保留一个VIEW,您可以将其用作查询中表格的替代品,以准备好这些数字:

CREATE VIEW address_history_nr AS
SELECT *, row_number() OVER (PARTITION BY person_id
                             ORDER BY address_history_id) AS adr_nr
FROM   address_history;

或者您可能想要ORDER BY其他内容。也许created_at?更好created_at, address_history_id打破可能的联系。相关回答:

此外,您要查找的数据类型为timestamptimestamptz,而不是Postgres中的 datetime

您只需要存储previous_address(或更多详细信息),而不是 address ,也不需要 original_address 。在理智的db布局中,两者都是多余的。