I was wondering should I separate table like below, or not?
Well, one immediately obvious downside of the table design you posted is that there are no constraints on user_information
or user_role
ensuring that you don't have more than one such row in each of these tables for each user. And even if you remember to add that, you will still have the problem that it will be difficult or impossible to enforce the rule "every user must have a role (or other critical attribute)".
Where it typically makes sense to break out metadata like this is when you have either many-to-one relationship of this metadata (e.g. a single user may have multiple roles), or you have a lot (i.e. many columns) of optional metadata that is unwieldy to cram into a single table.
For now I only can imagine I might want to know each column last modified time?
So if I want to know each column last modified time, is there any original build method in PostgreSQL? or I have to add for each column like email_last_modified_date, username_last_modified_date ...
You'll have to create individual columns (e.g. "email_last_modified_date"
) and have a trigger function enforce that the column is set correctly to achieve this. A more flexible and useful approach is usually constructing an audit table, with a trigger on the "user" table saving the changed columns for every UPDATE, or the contents of the whole row for every DELETE. This is where json, jsonb, or hstore types come in handy, if you'd like a single audit table capable of dealing with several tables, or capable of dealing with many columns from a single user
table without needing to know the structure of the user
table.
It seems there is a UNIQUE INDEX on table A(user_id) and you're trying to assign an existing value to more than one row.
Have a look at the next example:
create table a (id int, user_id int, f_id int);
create table b (id int, f_id int);
create unique index A_user_id_key on a(user_id);
insert into a
values (1, 1, 11),
(2, 3, 22),
(3, 2, 33),
(4, 5, 44 );
insert into b
values (1, 11),
(3, 22),
(3, 33), --<<<< there is another row with user_id = 3
(4, 44);
When I try to update using your current query:
update a
set user_id = b.id
from b
where a.f_id = b.f_id;
It returns same error message:
ERROR: duplicate key value violates unique constraint "a_user_id_key"
DETAIL: Key (user_id)=(3) already exists.
You could solve by avoiding existing values:
update a
set user_id = b.id
from b
where a.f_id = b.f_id
and not exists(select 1 from a where a.user_id = b.id);
This is the result:
select * from a;
id | user_id | f_id
-: | ------: | ---:
1 | 1 | 11
2 | 3 | 22
3 | 2 | 33
4 | 4 | 44
db<>fiddle here
But I'll suggest to check wich are the duplicate rows using next query:
select a.*
from a
join b
on a.f_id = b.f_id
and exists(select 1 from a where user_id = b.id and f_id <> b.f_id);
id | user_id | f_id
-: | ------: | ---:
3 | 2 | 33
db<>fiddle here
Best Answer
You can update tuples from multiple partitions in one statement.
If you are using declarative partitioning, then the ability to update tuples in a way that causes them to move partitions was added in v11. If you are using partitioning by inheritance, then what it does in this case is up to your triggers.