Insert into partition table postgresql - postgresql

everyone!
I'm trying to insert data from non-partition table t1 to a partition one t2 with
insert into t2 (select * from t1);
But I get an error: Partition key of the falling row contains (column_name) = (value)
What can be wrong?
t2 is partitioned by months by column date_name , not column_name
P.s. when I try to insert data from partition to partition table with the same way, I get the same error
Hoe should I insert data in partition table?
Version: Postgresql 11

There must be at least one row in t1 for which there is no matching partition in t2. You have to create all partitions for the table before you insert data.
To figure out which row gives you trouble, look at the value from the error message.

Related

How to get value list of list partitioning table of postgresql?

I am trying to use list partitioning in PostgreSQL.
https://www.postgresql.org/docs/current/ddl-partitioning.html
So, I have some questions about that.
Is there a limit on the number of values or partition tables in list partitioning?
When a partitioning table is created as shown below, can i check the value list with SQL? (like keys = [test, test_2])
CREATE TABLE part_table (id int, branch text, key_name text) PARTITION BY LIST (key_name);
CREATE TABLE part_default PARTITION OF part_table DEFAULT;
CREATE TABLE part_test PARTITION OF part_table FOR VALUES IN ('test');
CREATE TABLE part_test_2 PARTITION OF part_table FOR VALUES IN ('test_2');
When using the partitioning table created above, if data is added with key_name = "test_3", it is added to the default table. If 'test_3' exists in the default table and partitioning is attempted with the corresponding value, the following error occurs.
In this case, is there a good way to partition with the value 'test_3' without deleting the value in the default table?
CREATE TABLE part_test_3 PARTITION OF part_table FOR VALUES IN ('test_3');
Error: updated partition constraint for default partition "part_default" would be violated by some row
Is it possible to change the table name or value of a partition table?
Thank you..!
Is there a limit on the number of values or partition tables in list
partitioning?
Some test: https://www.depesz.com/2021/01/17/are-there-limits-to-partition-counts/
The value in current table and value reside in which partition.
SELECT
tableoid::pg_catalog.regclass,
array_agg(DISTINCT key_name)
FROM
part_table
GROUP BY
1;
To get all the current partition, and the configed value range. Use the following.
SELECT
c.oid::pg_catalog.regclass,
c.relkind,
inhdetachpending as is_detached,
pg_catalog.pg_get_expr(c.relpartbound, c.oid)
FROM pg_catalog.pg_class c, pg_catalog.pg_inherits i
WHERE c.oid = i.inhrelid
AND i.inhparent = '58281'
--the following query will return 58281.
select c.oid
from pg_catalog.pg_class c
where relname ='part_table';

How can I add values from other columns and other tables into into this correlated subquery?

How can I include worker name and department name column from the other table into the correlated subquery below? The table should show the worker id and names from workers whose work is not null.
Table Worker:
col:name
Schmitz
Wolfgang
Table: Department
col: dept_name
Counselling
Diagnosis
Table Work:
col:work
project leader
group leader
null
project leader
The correlated subquery below is from the table 'Work'.
select worker_id from work AS a
where not work is null and exists
(select *
from work as b
where a.worker_id = b.worker_id
and a.work != b.work
)
I have tried with nested subqueries and still does not work.

Exchange & split partition have a issue

I am trying to exchange non partition data with partition data. I have done following steps.
Created a new table TEMP_TABLE with partition with the TEMP_TABLE_1 range as date('1-09-2019').
And I have used
ALTER TABLE TEMP_TABLE
EXCHANGE PARTITION TEMP_TABLE_1
WITH TABLE ORG_TABLE
WITHOUT VALIDATION
UPDATE GLOBAL INDEXES;
With this my table data is exchanged with the partition and new table I can see the partition with data.
But now the problem is that the data contains rows with date more than 1-09-2019, when I try
select count(*) from TEMP_TABLE where date > '1-09-2019';
its giving 0 though there is data with the date till today.
If I try to split this partition
ALTER TABLE TEMP_TABLE SPLIT PARTITION TEMP_TABLE_1 INTO (PARTITION
TEMP_TABLE_2 values LESS THAN (TO_DATE('01-OCT-2019 00:00:00', 'DD-MON-
YYYY HH24:MI:SS')), PARTITION TEMP_TABLE_1) UPDATE GLOBAL INDEXES
PARALLEL 4;
Its throwing partition cannot be split along the specified high bound.
How to get the data which is more than the range date i have provided.
As you are exchanging data without validation (probably to improve performance) Oracle won't validate whether the value for partition key column of the data that is inserted matches the partition range condition of the partition into which that data is inserted.
--partitioned table
create table mytabp(n date)
partition by range(n)
interval(numtodsinterval(1, 'DAY'))
(partition p0 values less than (to_date('20190901','yyyymmdd')));
--nonpartitioned table to hold the data outside partition range
create table temp_mytab(n date);
insert into temp_mytab values(to_date('20191001','yyyymmdd'));
--exchanging without validation
alter table mytabp exchange partition p0 with table temp_mytab without validation;
--Data exists
select count(1) from mytabp;--1
Due to partition pruning in the below query the record is searched in the partition which must hold this data by definition. As the record exists in an incorrect partition that data is not returned.
select count(1) from mytabp where n > to_date('20190901','yyyymmdd');--0
By applying TRUNC on partitioned column, Oracle is presented with an option to scan all partitions. So the below SQL produces the record. For me on Oracle 12cR1 on Exadata, the subsequent executions of this SQL with TRUNC scanned the exact partition where the record was sitting and did not scan all partitions. I checked this with my explain plan's PARTITON_START and PARTITION_STOP columns.
select count(1) from mytabp where trunc(n) > to_date('20190901','yyyymmdd');--1
By design it is bad to place data on incorrect partitions. Please validate or filter for the correct data before executing exchange without validation.

PostgreSQL OFFSET field consistency across processes

I'm trying to copy a Postgres table1 to another table2 while changing the value of one of the columns. To make the transfer faster I run 10 different processes each having different offsets in the table1 to start from, e.g., 1st process: SELECT * FROM table OFFSET offset1 LIMIT x; then copy to table2, 2nd process: SELECT * FROM table OFFSET offset2 LIMIT x then copy to table2.
But even though I don't have duplicate rows in my table1 I do get duplicate rows in my table2 (x is smaller than offset2-offset1). Is it possible that the same offset value is not pointing to the same row in the table across different processes? If yes, what would be better way to copy a table while modifying a column in Postgres? Thanks!
Without an order by statement, limit and offset are seldom meaningful... SQL offers no guarantee on row order unless you make it explicit. So add an order by clause.
Also, if copying a table wholesale is what you want, it's better to simply:
insert into table2 select * from table1

Insert data into table effeciently, postgresql

I am new to postgresql (and databases in general) and was hoping to get some pointers on improving the efficiency of the following statement.
I am inserting data from one table to another, and do not want to insert duplicate values. I have a rid (unique identifier in each table) that are indexed and are Primary Keys.
I am currently using the following statement:
INSERT INTO table1 SELECT * FROM table2 WHERE rid NOT IN (SELECT rid FROM table1).
As of now the table one is 200,000 records, table2 is 20,000 records. Table1 is going to keep growing (probably to around 2,000,000) and table2 will stay around 20,000 records. As of now the statement takes about 15 minutes to run. I am concerned that as Table1 grows this is going to take way to long. Any suggestions?
This should be more efficient than your current query:
INSERT INTO table1
SELECT *
FROM table2
WHERE NOT EXISTS (
SELECT 1 FROM table1 WHERE table1.rid = table2.rid
);
insert into table1
select t2.*
from
table2 t2
left join
table1 t1 on t1.rid = t2.rid
where t1.rid is null