使用默认分区中已存在的值创建新的表分区

mos*_*evi 4 postgresql migration partitioning default-value postgresql-11

我有下表:

CREATE TABLE orders
(
  info_date  date,
  country_code  VARCHAR,
  order_total   int,
  CONSTRAINT orders_pk PRIMARY KEY (info_date, country_code)
) PARTITION BY LIST (country_code);

CREATE TABLE orders_def PARTITION OF orders DEFAULT;
Run Code Online (Sandbox Code Playgroud)

我插入一些行country_code 'foo',它们最终位于默认分区中。

一段时间后,我决定应该'foo'有自己的分区,我该怎么做?

根据文档:

如果存在 DEFAULT 分区,并且 DEFAULT 分区中存在任何行,否则它们将适合要添加的新分区,则无法添加新分区。


这是我的尝试

begin;
CREATE TEMP TABLE temp_table ON COMMIT DROP AS 
SELECT * FROM orders where country_code = 'foo';
DELETE FROM orders where country_code = 'foo';
CREATE TABLE orders_foo PARTITION OF orders FOR VALUES IN ('foo');
INSERT INTO orders_foo select * from temp_table;
commit;
Run Code Online (Sandbox Code Playgroud)

然而这看起来像是一个黑客。

jja*_*nes 5

非黑客行为是首先不要陷入这种情况,当您不确定这是否是您想要的永久分区时,不使用默认分区。当我们无法正确预见未来时,有时我们不得不诉诸黑客手段。

您可以通过填充永久表,然后将其附加为新分区来稍微减少黑客攻击,而不是使用临时表来处理数据的输出和输入。

begin;
CREATE TABLE orders_foo (like orders); 
INSERT into orders_foo SELECT * FROM orders where country_code = 'foo';
DELETE FROM orders where country_code = 'foo';
ALTER TABLE orders ATTACH PARTITION orders_foo FOR VALUES IN ('foo');
commit;
Run Code Online (Sandbox Code Playgroud)

您还可以将 INSERT 和 DELETE 合并到一条语句中,但我不知道这是否真的能给您带来任何有价值的东西,除了避免一次拼错“foo”的机会。

with t as (delete from orders where country_code='foo' returning *) 
   insert into  orders_bar select * from t;
Run Code Online (Sandbox Code Playgroud)