Postgres constraint: row with flag true must exist before false can - postgresql

I have a database schema that looks something like this:
- Table: User
- Column: id, primary key
- Table: UserAlias
- Column: userId, foreign key
- Column: isPrimary, boolean
I want to make it so that users have to have a primary alias, but cannot make a secondary one until they already have a primary one.
Is it possible to structure a constraint like this? Maybe a recursive foreign key constraint can work? Thanks!

Related

Ansible postgresql_table: how to create a foreign key constraint?

Creating databases and tables using the postgresql module in Ansible is pretty straight forward and works great, but I canĀ“t really figure out how to create a foreign key constraint.
Eg. I create a table in Ansible like this:
- name: "Create foo table"
become: yes
become_user: postgres
community.postgresql.postgresql_table:
db: test_db
owner: postgres
name: foo
columns:
- id bigserial PRIMARY KEY NOT NULL
- bar_id bigint
Now I would like to create a foreign key constraint that references the id column in the table bar. In Postgresql I could add a foreign key constrain this like this:
ALTER TABLE foo ADD CONSTRAINT bar_id_fkey FOREIGN KEY (bar_id) REFERENCES bar (id) MATCH FULL;
How can this be done in Ansible?
You can create a foreign key constraint when you create the table by adding a CONSTRAINT to the columns list, like this:
- name: "Create foo table"
become: yes
become_user: postgres
community.postgresql.postgresql_table:
db: test_db
owner: postgres
name: foo
columns:
- id bigserial PRIMARY KEY NOT NULL
- bar_id bigint
- CONSTRAINT bar_id_fkey FOREIGN KEY (bar_id) REFERENCES bar (id) MATCH FULL;
Or just include the constraint in the column definition:
- name: "Create foo table"
become: yes
become_user: postgres
community.postgresql.postgresql_table:
db: test_db
owner: postgres
name: foo
columns:
- id bigserial PRIMARY KEY NOT NULL
- bar_id bigint REFERENCES bar(id) MATCH FULL
But you cannot add a constraint after the fact using the
postgresql_table module: it doesn't support the use of ALTER TABLE
to synchronize the database table with changes in your playbook.
From the documentation, the postgresql_table module can be used to
"change some table attributes", but looking at the source that appears
to be limited to:
Renaming the table
Changing the table owner
Changing the tablespace
Changing store parameters

PostgreSQL declarative partition - unique constraint on partitioned table must include all partitioning columns [duplicate]

This question already has an answer here:
ERROR: unique constraint on partitioned table must include all partitioning columns
(1 answer)
Closed last month.
I'm trying to create a partitioned table which refers to itself, creating a doubly-linked list.
CREATE TABLE test2 (
id serial NOT NULL,
category integer NOT NULL,
time timestamp(6) NOT NULL,
prev_event integer,
next_event integer
) PARTITION BY HASH (category);
Once I add primary key I get the following error.
alter table test2 add primary key (id);
ERROR: unique constraint on partitioned table must include all partitioning columns
DETAIL: PRIMARY KEY constraint on table "test2" lacks column "category" which is part of the partition key.
Why does the unique constrain require all partitioned columns to be included?
EDIT: Now I understand why this is needed: https://www.postgresql.org/docs/current/ddl-partitioning.html#DDL-PARTITIONING-DECLARATIVE-LIMITATIONS
Once I add PK with both columns it works.
alter table test2 add primary key (id, category);
But then adding the FK to itself doesn't work.
alter table test2 add foreign key (prev_event) references test2 (id) on update cascade on delete cascade;
ERROR: there is no unique constraint matching given keys for referenced table "test2"
Since PK is not just id but id-category I can't create FK pointing to id.
Is there any way to deal with this or am I missing something?
I would like to avoid using inheritance partitioning if possible.
EDIT2: It seems this is a known problem. https://www.reddit.com/r/PostgreSQL/comments/di5mbr/postgresql_12_foreign_keys_and_partitioned_tables/f3tsoop/
Seems that there is no straightforward solution. PostgreSQL simply doesn't support this as of v14. One solution is to use triggers to enforce 'foreign key' behavior. Other is to use multi-column foreign keys. Both are far from optimal.

Dropping Unique Constraint - PostgreSQL

TL;DR
I am seeking clarity on this: does a FOREIGN KEY require a UNIQUE CONSTRAINT on the other side, specifically, in Postgres and, generally, in relational database systems?
Perhaps, I can test this, but I'll ask, if the UNIQUE CONSTRAINT is required by the FOREIGN KEY what would happen if I don't create it? Will the Database create one or will it throw an error?
How I got there
I had earlier on created a table with a column username on which I imposed a unique constraint. I then created another table with a column bearer_name having a FOREIGN KEY referencing the previous table's column username; the one which had a UNIQUE CONSTRAINT.
Now, I want to drop the UNIQUE CONSTRAINT on the username column from the database because I have later on created a UNIQUE INDEX on the same column and intuitively I feel that they serve the same purpose, or don't they? But the database is complaining that the UNIQUE INDEX has some dependent objects and so it can't be dropped unless I provide CASCADE as an option in order to drop even the dependent object. It's identifying the FOREIGN KEY on bearer_name column in the second table as the dependent object.
And is it possible for the FOREIGN KEY to be a point to the UNIQUE INDEX instead of the UNIQUE CONSTRAINT?
I am seeking clarity on this: does a FOREIGN KEY require a UNIQUE CONSTRAINT on the other side
No it does not require only UNIQUE CONSTRAINT. It could be PRIMARY KEY or UNIQUE INDEX.
Perhaps, I can test this, but I'll ask, if the UNIQUE CONSTRAINT is required by the FOREIGN KEY what would happen if I don't create it? Will the Database create one or will it throw an error?
CREATE TABLE tab_a(a_id INT, b_id INT);
CREATE TABLE tab_b(b_id INT);
ALTER TABLE tab_a ADD CONSTRAINT fk_tab_a_tab_b FOREIGN KEY (b_id)
REFERENCES tab_b(b_id);
ERROR: there is no unique constraint matching given keys
for referenced table "tab_b"
DBFiddle Demo
And is it possible for the FOREIGN KEY to be a point to the UNIQUE INDEX instead of the UNIQUE CONSTRAINT?
Yes, it is possible.
CREATE UNIQUE INDEX tab_b_i ON tab_b(b_id);
DBFiddle Demo2

How do I set a default value for a UUID primary key column in Postgres?

I'm using PostgreSQL. I'm trying to create a primary key column taht is a UUID, so I ran this statement
ALTER TABLE my_object_times ADD PRIMARY KEY (id) DEFAULT uuid_generate_v4();
but I get the error
PG::SyntaxError: ERROR: syntax error at or near "DEFAULT"
What is the proper way to write the above statement (I'm doing alter because I'm changing an existing primary key column)?
If the column id already exists in the table and you want to modify it by making it the primary key and adding a default value, you can do it in 2 steps:
ALTER TABLE my_object_times ADD PRIMARY KEY (id);
ALTER TABLE my_object_times ALTER COLUMN id SET DEFAULT uuid_generate_v4();
If the column doesn't exist at all, then you can create it with all the attributes you want, by simply doing:
ALTER TABLE my_object_times ADD id uuid PRIMARY KEY DEFAULT uuid_generate_v4();
(I cannot test this right now but it should work)
In order to use uuid_generate_v4(), you first need to execute:
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";

Why is this compound primary key not working as expected?

I have a table "tbl_project_user_assignment" with a compound primary key.
It is made up of project_id and user_id
Each of these are also a foreign key to the project and user tables respectively.
At the moment, I have 2 entries in this table as below...
project_id | user_id
--------------------
1 | 1
1 | 2
When I run this sql query...
INSERT INTO
tbl_project_user_assignment
(project_id, user_id) VALUES (2, 1);
...I get the following error message:
Integrity constraint violation: 1062
Duplicate entry '1' for key
'FK_project_user'
The FK_project_user key is the one linking the project_id to the tbl_project id.
This doesn't make sense to me because the values I'm inserting are unique...
Any ideas?
It looks like FK_project_user is a unique key. Try dropping temporarily that constraint and perform the insert again.
If insert works, recreate the constraint making sure it's not flagged as unique anymore.
I think you should have:
a foreign key relation to project
a foreign key relation to user
a unique constraint on (project, user)
possibly a primary key on the combination of (project, user) OR a separate key field
If you choose a combined PK you wouldn't need an extra constraint of course.
And it seems you have a unique constraint on user (by itself).
Posting the show create table statement would help even more.