在 PostgreSQL 中,根据特定的列排序/排序添加具有唯一值的列

In PostgreSQL, add a column with unique values according to specific column ordering / sorting

背景

我有一个 PostgreSQL table,db1,里面有几个列,但没有主键。我需要添加一个。 Postgres 是版本 13-point-something,运行ning 在 64 位 Windows PC 上的本地服务器上。这是 table:

的玩具版本
+-------------------+------------+
|member             |service_date|
+-------------------+------------+
|eof81j4            |2011-01-06  |
|eof81j4            |2010-06-03  |
|eof81j4            |2010-01-12  |
|eof81j4            |2011-05-21  |
|j42roit            |2015-11-29  |
|j42roit            |2015-11-29  |
|j42roit            |2015-11-29  |
|p8ur0fq            |2014-01-13  |
|p8ur0fq            |2016-04-04  |
|p8ur0fq            |2014-01-13  |
|vplhbun            |2019-08-15  |
|vplhbun            |2019-08-15  |
|vplhbun            |2019-08-15  |
|akj3vie            |2009-03-31  |
+-------------------+------------+

请注意,table 没有以任何明显的方式排序:member 列不是 ABC 顺序,例如,service_date 列不是按时间顺序或任何顺序排列。

问题

通常,我会像这样向 table 添加一个主键:

ALTER TABLE db1 ADD COLUMN id SERIAL PRIMARY KEY

这很好用。但是,由于稍后我必须 运行 进行一些查询,我希望应用主键,就好像 table 首先由 [=15= 排序(换句话说,排序)一样](按字母顺序升序),并在其中按时间顺序(从最旧到最新)按 service date。换句话说,我想要这样的东西:

+-------------------+------------+--+
|member             |service_date|id|
+-------------------+------------+--+
|akj3vie            |2009-03-31  |1 |
|eof81j4            |2010-01-12  |2 |
|eof81j4            |2010-06-03  |3 |
|eof81j4            |2011-01-06  |4 |
|eof81j4            |2011-05-21  |5 |
|j42roit            |2015-11-29  |6 |
|j42roit            |2015-11-29  |7 |
|j42roit            |2015-11-29  |8 |
|p8ur0fq            |2014-01-13  |9 |
|p8ur0fq            |2014-01-13  |10|
|p8ur0fq            |2016-04-04  |11|
|vplhbun            |2019-08-15  |12|
|vplhbun            |2019-08-15  |13|
|vplhbun            |2019-08-15  |14|
+-------------------+------------+--+

我试过的

破解这个的尝试是这样的:

ALTER TABLE db1 ADD COLUMN id SERIAL PRIMARY KEY ORDER BY member, service_date 

但这会产生 [42601] ERROR: syntax error at or near "ORDER"。我在 SO 上寻找过类似的 posts,但解决方案似乎涉及创建一个新的 table,我不想那样做(因为真正的 table 我将要执行此操作非常非常大)。

编辑

经过深思熟虑,部分归功于 Gordon Linoff 在下面的回答,我意识到我实际上不需要这个新列作为 Postgres 识别的正式意义上的主键。我 真正 需要的只是一列,其中每一行的值都按照我描述的方式排序。是不是正式PK其实并不重要。 (在这个 post 的原始标题和 body 中,我曾要求提供主键。我已经编辑了一些内容以反映这不是绝对必要的。)

一种方法是添加 id 列,设置值,然后将其转换为标识。您必须小心,因为您希望编号从 15 开始(对于您的示例数据):

alter table db1 add column id int not null default 0;
update db1
    set id = d.new_id
    from (select db1.*, db1.ctid, row_number() over (order by member, service_date) as new_id
          from db1
         ) d
    where db1.ctid = d.ctid;

alter table db1 alter column id drop default;

alter table db1 alter column id add generated always as identity  (start with 15) ;

alter table db1 add primary key (id);

Here 是一个 db<>fiddle.