When dropping constraints from a postgres table , How to know the safest order to drop the constraints. Like ,
1) The foreign key constraints can be dropped first [as they have to be droppped before primary key constraint]
Then the order of removing the constraints can be in any order . like check constraint, unique constraint, not nulls, default , primary key constraints . Am I correct
No constraint on a PostgreSQL table depends on another constraint on the same table, so the order does not matter here.
The only dependency between constraints is the dependency of a foreign key on the primary or unique key on the target table.
So you can either remove all foreign key constraints first and then all other constraints, or you can use ALTER TABLE ... DROP CONSTRAINT ... CASCADE which will automatically drop all dependent constraints, then you don't have to care about the order at all.
Related
I have a table named base_types that contains this constraint:
ALTER TABLE public.base_types
ADD CONSTRAINT base_type_gas_type_fk FOREIGN KEY (gas_type)
REFERENCES public.gas_types (gas_type) MATCH SIMPLE
ON UPDATE NO ACTION
ON DELETE NO ACTION
DEFERRABLE INITIALLY DEFERRED;
And I have a table named alarm_history that contains five constraints, including this one:
ALTER TABLE public.alarm_history
ADD CONSTRAINT alarm_history_device_fk FOREIGN KEY (device)
REFERENCES public.bases (alarm_device) MATCH SIMPLE
ON UPDATE NO ACTION
ON DELETE NO ACTION
DEFERRABLE INITIALLY DEFERRED;
I am trying to convert a database from one that didn't bother with anything weird and useless like constraints into one that uses them. I am beginning with this script:
delete from gas_types;
select conversion.convert_base_types();
alter table base_types validate constraint base_type_gas_type_fk;
select conversion.convert_alarm_history();
alter table alarm_history validate constraint alarm_history_base_fk;
alter table alarm_history validate constraint alarm_history_charge_fk;
alter table alarm_history validate constraint alarm_history_cooler_fk;
alter table alarm_history validate constraint alarm_history_device_fk;
alter table alarm_history validate constraint alarm_history_furnace_fk;
I duly get an error message telling me that the gas_type field in my new base_types record doesn't match anything in the gas_types table, since the gas_types table is empty. But if I comment out the base_types commands, I get 18,000 nice, shiny new records in the alarm_history table, despite the fact that every single one of them violates at least one of that table's five foreign key constraints, since all of the tables those keys are referring to are empty. I need to ensure that my converted data is consistent, and therefore I need to validate my constraints, but that's obviously not happening. Why not?
Since the constraints above are created as DEFERRABLE INITIALLY DEFERRED, they are not checked until the DML statements (your delete statement) are committed or in your case you until you explicitly validate the constraint.
This is the normal and expected operation of an initially deferred deferrable constraint.
To change this functionality within your current transaction you can issue a SET CONSTRAINTS command to alter this:
SET CONSTRAINTS alarm_history_device_fk IMMEDIATE;
delete from gas_types;
Which should raise a foreign key violation alerting you earlier that you have data dependent on the records you are tying to delete.
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 to set FOREIGN KEY (packet_id) REFERENCES girvi_packet(id) DEFERRABLE INITIALLY DEFERRED to NULL ?
If parent get deleted postgreSQL raises error that parent is missing I want to suppress this behavior. This constraint is added by default by some 3rd part tool. But my use case demands otherwise.
The purpose of the foreign key is to prevent orphan children. The only way you can do is to delete the constrain
ALTER TABLE ... DROP CONSTRAINT ...
In order to delete some rows referenced by a foreign key constraint without cascading on delete, I created a temporary foreign key constraint, deleted the row, and then deleted the temporary constraint:
ALTER TABLE rel_user_right
ADD CONSTRAINT temp_fk_rel_user_right_user_right_02
FOREIGN KEY (right_id) REFERENCES user_right (id)
ON DELETE CASCADE;
DELETE FROM user_right WHERE "name" LIKE '%.statusLight.%';
ALTER TABLE rel_user_right
DROP CONSTRAINT temp_fk_rel_user_right_user_right_02;
where this table already had the following constraint defined on it:
ALTER TABLE rel_user_right
ADD CONSTRAINT fk_rel_user_right_user_right_02
FOREIGN KEY (right_id) REFERENCES user_right (id);
This worked fine for me, but seems to have failed on my colleague's computer. As you can see, the two FK constraints define conflicting ON DELETE behaviour. Is precedence defined in this situation, or is it non-deterministic?
Postgres allows to create two references differing only in ON DELETE clause.
I could find no information on the impact of such a case.
In my tests I was unable to cover the existing constraint with new one (i.e. DELETE was always restricted despite of the existence of the second cascading constraint).
However this behaviour is undocumented and one should not rely on it.
The normal way to proceed should be replacing the old constraint with new one:
ALTER TABLE rel_user_right
ADD CONSTRAINT fk_rel_user_right_user_right_temp
FOREIGN KEY (right_id) REFERENCES user_right (id)
ON DELETE CASCADE,
DROP CONSTRAINT fk_rel_user_right_user_right;
DELETE FROM user_right WHERE "name" LIKE '%.statusLight.%';
ALTER TABLE rel_user_right
ADD CONSTRAINT fk_rel_user_right_user_right
FOREIGN KEY (right_id) REFERENCES user_right (id),
DROP CONSTRAINT fk_rel_user_right_user_right_temp;
DISABLE CONSTRAINT would be useful here, but there is no such feature in Postgres (there have been attempts to implement it, but they did not end in success). You can use DISABLE TRIGGER for it, but the above solution is simpler and more natural.
Can I drop primary key index without dropping primary key constraint in postgresql?
Your question is a bit confusing. I think you must mean this:
Can I drop an index on a column but still keep the uniqueness constraint on that column?
No. A uniqueness constraint requires an index. You can make your constraint into an ordinary non-primary index, but you can't make it not an index.
Also, read about primary keys in the documentation:
Technically, a primary key constraint is simply a combination of a unique constraint and a not-null constraint.
So if a column is a primary key it has by definition a unique constraint and therefore also an index. You cannot have a primary key that isn't an index.