PostgreSQL: Partition table by external (non-column) value - postgresql

I want to split up a table into partitions, where I have a partition for each distinct value of a column. So, if foo_id is the column, I want to put a row with foo_id=23 into the partition bar_23. Is it possible to then remove the column from the partitions and still use the value for selecting the partition via constraints or do I have to explicitly name the partition table in the query?
I.e., can I do this
INSERT INTO bar (foo_id, other) (23, 'value');
without actually having foo_id in the table? Or do I have to go the explicit way:
INSERT INTO bar_23 (other) ('value');

Related

Renaming postgres parent table with child partitions

is it ok to rename a parent table from which partitioned child tables are based ?
For example if I have
CREATE TABLE demos_qa (
demo_id int,
demo_date VARCHAR,
demo_text TEXT)
PARTITION BY RANGE (trxn_post_dt);
CREATE TABLE demos_2022 PARTITION OF demos_qa
FOR VALUES FROM ('2022-01-01') TO ('2023-01-01');
CREATE TABLE demos_2021 PARTITION OF demos_qa
FOR VALUES FROM ('2021-01-01') TO ('2022-01-01');
CREATE TABLE demos_2020 PARTITION OF demos_qa
FOR VALUES FROM ('2020-01-01') TO ('2021-01-01');
and I bulk load the partition tables.
I now want to rename the parent table from demo_qa to demo. Can I do that and will things work as normal without having to change the definitions of the partition tables ?
Yes, this will work.
The partitions won't be renamed though, in case you expected that.

Range Partitions by Date with One Partition for NULL dates

I would like to have a table with deleted column containing the date the item was soft-deleted. Rows with NULL value in deleted column are the active ones. I was not able to figure our the syntax to create a partition for null values in deleted column. What is the syntax of creating such column?
create table my_table_pointing(street_id int, p_city_id int, name varchar(10), deleted date)
PARTITION BY RANGE (deleted);
CREATE TABLE my_table_pointing_2020 PARTITION OF my_table_pointing
FOR VALUES FROM ('2020-01-01') TO ('2021-01-01');
CREATE TABLE my_table_pointing_active PARTITION OF my_table_pointing
"for all rows where date is null"...
Thanks!
Provided you are on PG11 or later, you can create a default partition, and rows with deleted is null will be routed there.
create table my_table_pointing_active partition of my_table_pointing default;

How to update a hash partitioned column in Oracle 12c?

I have a table that is partitioned by hash on a column.
CREATE TABLE TEST(
ACCOUNT_NUMBER VARCHAR(20)
)
PARTITION BY HASH (ACCOUNT_NUMBER)
PARTITIONS 16
Now, I want to update the account_number column itself in the table because of certain requirements.
As this column is partitioned, I'm not able to issue an update command on the table like
Update test set account_number = new_value
as it results to the below error:
Error is: ORA-14402: UPDATING PARTITION WOULD CAUSE PARTITION CHANGE.
Row movement is set to disable for the table.
The one way I know is to enable row movement but I also want to explore other options.
Could you please advise me on how to solve this?

Attach partition LIST to existing table in postgres 11

I am trying to ALTER a table to use partitions LIST in postgres 11. I have been trying for hours but i keep getting errors.
I have a huge table, clients, with ( client_id, customer_id, value).
I have already created a new empty table, clients, by renaming the old table to clients_old and then created the new table with: CREATE TABLE clients( like clients_old including all).
And from here I am stuck when trying to add the LIST partition.
I have tried to:
ALTER TABLE Clients attach PARTITION BY LIST (client_id) --> fail;
ALTER TABLE Clients attach PARTITION LIST (client_id) --> fail;
ALTER TABLE Clients ADD PARTITION LIST (client_id) --> fail;
What syntax should I use to alter the table to use partitions?
Quote from the manual
It is not possible to turn a regular table into a partitioned table or vice versa
So, you can not change an existing non-partitioned table to a partitioned table.
You need to create a new table (with a different name) that is partitioned, create all necessary partitions and then copy the data from the old table to the new, partitioned table.
Something like:
create table clients_partitioned
(
.... all columns ...
)
PARTITION BY LIST (client_id);
Then create the partitions:
create table clients_1
partition of clients_partioned
for values in (1,2,3);
create table clients_1
partition of clients_partioned
for values in (4,5,6);
Then copy the data:
insert into clients_partitioned
select *
from clients;
Once that is done, you can drop the old table and rename the new table:
drop table clients;
alter table clients_partitioned rename to clients;
Don't forget to re-create your foreign keys and indexes.
I had to add for tag in order to add the partition:
create table clients_1
partition of clients_partioned
for values in (4,5,6);
because without for was a syntax error.

PostgreSQL partitioning syntax FOR VALUES

I'm working on table partitioning in PostgreSQL.
I created a partition for my master table:
CREATE TABLE head_partition_table PARTITION OF master_table
FOR VALUES FROM (DATE_START) TO (DATE_END)
PARTITION BY RANGE (ENTITY_ID, GROUP_NAME);
After that, I want to divide head_partition_table into smaller partitions, so I wrote code:
CREATE TABLE subpartition_table OF head_partititon_table
FOR VALUES FROM ('0', 'A') TO ('0', 'Z');
I can't find how I can specify individual values rather than a range.
Something like
CREATE TABLE subpartition_table OF head_partititon_table
FOR VALUES ('0', 'A');
CREATE TABLE subpartition_table OF head_partititon_table
FOR VALUES ('0', 'Z');
I get a syntax error at or near "(".
Is this possible?
P.S. I tried PARTITION BY LIST, but in that case, I can use just one field.
You could partition these by list like you want by introducing another layer of partitions:
CREATE TABLE head_partition_table PARTITION OF master_table
FOR VALUES FROM ('2019-01-01') TO ('2020-01-01')
PARTITION BY LIST (entity_id);
CREATE TABLE subpartition1 PARTITION OF head_partition_table
FOR VALUES IN ('0')
PARTITION BY LIST (group_name);
CREATE TABLE subsubpartition1 PARTITION OF subpartition1
FOR VALUES IN ('A');
But this is more an academic exercise than something useful.
Anything exceeding a at most few hundred partitions will not perform well at all.