PostgreSQL 将 SERIAL 列添加到现有表中,其值基于 ORDER BY

sea*_*lor 5 postgresql

我有一个大表(6+ 百万行),我想添加一个自动递增整数列sid,其中sid基于ORDER BY inserted_at ASC. 换句话说,最旧的记录inserted_at将设置为1总记录数,最新的记录将设置为总记录数。关于我如何处理这个问题有什么建议吗?

unu*_*tbu 6

添加一sid列并UPDATE SET ... FROM ... WHERE

UPDATE test
SET sid = t.rownum
FROM (SELECT id, row_number() OVER (ORDER BY inserted_at ASC) as rownum
    FROM test) t
WHERE test.id = t.id
Run Code Online (Sandbox Code Playgroud)

请注意,这依赖于主键id. (如果您的表还没有主键,则必须先创建一个。)


例如,

-- create test table
DROP TABLE IF EXISTS test;
CREATE TABLE test (
    id int PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY
    , foo text
    , inserted_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP
);
INSERT INTO test (foo, inserted_at) VALUES
('XYZ', '2019-02-14 00:00:00-00')
, ('DEF', '2010-02-14 00:00:00-00')
, ('ABC', '2000-02-14 00:00:00-00');

-- +----+-----+------------------------+
-- | id | foo |      inserted_at       |
-- +----+-----+------------------------+
-- |  1 | XYZ | 2019-02-13 19:00:00-05 |
-- |  2 | DEF | 2010-02-13 19:00:00-05 |
-- |  3 | ABC | 2000-02-13 19:00:00-05 |
-- +----+-----+------------------------+

ALTER TABLE test ADD COLUMN sid INT;

UPDATE test
SET sid = t.rownum
FROM (SELECT id, row_number() OVER (ORDER BY inserted_at ASC) as rownum
    FROM test) t
WHERE test.id = t.id
Run Code Online (Sandbox Code Playgroud)

产量

+----+-----+------------------------+-----+
| id | foo |      inserted_at       | sid |
+----+-----+------------------------+-----+
|  3 | ABC | 2000-02-13 19:00:00-05 |   1 |
|  2 | DEF | 2010-02-13 19:00:00-05 |   2 |
|  1 | XYZ | 2019-02-13 19:00:00-05 |   3 |
+----+-----+------------------------+-----+
Run Code Online (Sandbox Code Playgroud)

最后,创建sidSERIAL(或者更好的是 IDENTITY 列):

ALTER TABLE test ALTER COLUMN sid SET NOT NULL;
-- IDENTITY fixes certain issue which may arise with SERIAL
ALTER TABLE test ALTER COLUMN sid ADD GENERATED BY DEFAULT AS IDENTITY;
-- ALTER TABLE test ALTER COLUMN sid SERIAL;
Run Code Online (Sandbox Code Playgroud)