I am copying data from one PostgreSQL v10 table to another. The destination table has several foreign key constraints. I was surprised that I did not get any errors, even though none of the tables referred to by the foreign key constraints had any data.
Before I did the copy, I used DISABLE TRIGGER ALL to ensure that the trigger defined on the destination table did not fire. I was surprised that the copy succeeded. After ENABLE TRIGGER ALL, I tried to add one more row, a copy of an existing row. That failed with a foreign key constraint violation. I then did DISABLE TRIGGER ALL, tried to add the new row, and it succeeded.
I conclude that in PostgreSQL 10, DISABLE TRIGGER ALL will disable foreign key constraint checks. Is that expected behavior?
Details can be found here.
Yes, that's expected.
From "ALTER TABLE":
DISABLE/ENABLE [ REPLICA | ALWAYS ] TRIGGER
These forms configure the firing of trigger(s) belonging to the table. (...) One can disable or enable a single trigger specified by name, or all triggers on the table, or only user triggers (this option excludes internally generated constraint triggers such as those that are used to implement foreign key constraints or deferrable uniqueness and exclusion constraints). Disabling or enabling internally generated constraint triggers requires superuser privileges; it should be done with caution since of course the integrity of the constraint cannot be guaranteed if the triggers are not executed. (...)
Related
I have the problem similar to this one SQL Server foreign key conflict in a multi values statement? However, in sql server 2008.
While I am reading data from csv file, there is some id already not exist in parent and thus return this error:
INSERT statement conflicted with the FOREIGN KEY constraint
May I know if there is a way similar to MySQL insert ignore. Such that I can simply skip the problematic data.
I accept that if there is no method other than creating a stored procedure with a new temp table (insert into a table without foreign key first, and then re-insert with where foreign_id exists in (select id from parent)).
As I really cannot find any in documentation, asking for ensuring I didn't miss anything.
One general solution which comes to mind would be to temporarily turn off the foreign key constraints, and do the insert. Then, afterwards, you may run a cleanup script/query to remove or rectify child records which are pointing to parents which do not exist. Once your data is in good shape, then turn on the foreign key constraints again.
Read How can foreign key constraints be temporarily disabled using T-SQL? to learn how to disable/enable a foreign key constraint for a single table:
ALTER TABLE MyTable NOCHECK CONSTRAINT MyConstraint -- disable
ALTER TABLE MyTable WITH CHECK CHECK CONSTRAINT MyConstraint -- enable
When I try to disable the constraint I am getting the following error
cannot disable constraint (SCOTT.EMPLOYEE_PK) - dependencies exist
Please give me the solution for this problem.
Can I use CASCADE to disable the constraint?
If I use CASCADE, then will I able to enable the constraint again?
According to the documentation the action to do is:
Either disable the foreign key constraints or use disable cascade
So use this to disable the primary key and its index:
alter table employee disable primary key
You can re-enable the index/constraint when done, but make sure you don't invalidate the index:
alter table employee enable primary key
Also read: Modifying, Renaming, or Dropping Existing Integrity Constraints.
Is there any difference between these two statements below?
ALTER TABLE [table_name] CHECK CONSTRAINT [constraint_name]
and
ALTER TABLE [table_name] WITH CHECK CHECK CONSTRAINT [constraint_name]
From Alter Table documentation:
WITH CHECK | WITH NOCHECK:
Specifies whether the data in the table is or is not validated against a newly added or re-enabled FOREIGN KEY or CHECK constraint. If not specified, WITH CHECK is assumed.
So, since the default is to do it "WITH CHECK", there is no difference at all.
The WITH CHECK clause will check any existing data and fail if there is data that doesn't meet the constraint. Without the WITH CHECK clause, the constraint will only apply to new data added to the table.
If the table has no data in it, then the statements are functionally equivalent.
Here is the documentation for the ALTER TABLE command in question:
http://msdn.microsoft.com/en-us/library/ms190273.aspx
It's a rather lengthy page, so I'll quote from it:
WITH CHECK | WITH NOCHECK
Specifies whether the data in the table is or is not validated against a newly added or re-enabled
FOREIGN KEY or CHECK constraint. If not specified, WITH CHECK is assumed for new constraints,
and WITH NOCHECK is assumed for re-enabled constraints.
It goes on to give this advice:
If you do not want to verify new CHECK or FOREIGN KEY constraints against existing data, use WITH
NOCHECK. We do not recommend doing this, except in rare cases. The new constraint will be
evaluated in all later data updates. Any constraint violations that are suppressed by WITH NOCHECK
when the constraint is added may cause future updates to fail if they update rows with data that
does not comply with the constraint.
I have the following code
--first statement
ALTER TABLE [nameOfMyTable] WITH CHECK ADD CONSTRAINT [nameOfMyConstraint] FOREIGN KEY([myFK])
REFERENCES [tableReference] ([myFK])
GO
--second statement
ALTER TABLE [nameOfMyTable] CHECK CONSTRAINT [nameOfMyConstraint]
GO
First, i define a CHECK constraint on a table. What does mean second statement?
The 2nd statement is redundant, the only time it would be needed is if the first statement had WITH NOCHECK. By default WITH CHECK is added if you don't explicitly state CHECK or NOCHECK in the ADD CONSTRAINT statement.
sql server management studio generate this code by default – Mikhail
Because the code is being auto generated it is just being constructed by a set of steps. Some of those steps will have some overlap so the "table definition" step may enable or disable the check the constraint while it creates the table, but the "setup constraints" step may also enable or disable the constraint.
Relevant documentation:
WITH CHECK | WITH NOCHECK
Specifies whether the data in the table is or is not validated against a newly added or re-enabled FOREIGN KEY or CHECK constraint.
If not specified, WITH CHECK is assumed for new constraints, and WITH
NOCHECK is assumed for re-enabled constraints.
If you do not want to verify new CHECK or FOREIGN KEY constraints against existing data, use WITH NOCHECK. We do not recommend doing
this, except in rare cases. The new constraint will be evaluated in
all later data updates. Any constraint violations that are suppressed
by WITH NOCHECK when the constraint is added may cause future updates
to fail if they update rows with data that does not comply with the
constraint.
The query optimizer does not consider constraints that are defined WITH NOCHECK. Such constraints are ignored until they are re-enabled
by using ALTER TABLE WITH CHECK CHECK CONSTRAINT ALL.
{ CHECK | NOCHECK } CONSTRAINT
Specifies that constraint_name is enabled or disabled. This option can only be used with FOREIGN KEY and CHECK constraints. When NOCHECK
is specified, the constraint is disabled and future inserts or updates
to the column are not validated against the constraint conditions.
DEFAULT, PRIMARY KEY, and UNIQUE constraints cannot be disabled.
From the docs:
Specifies that constraint_name is enabled or disabled. This option can only be used with FOREIGN KEY and CHECK constraints. When NOCHECK is specified, the constraint is disabled and future inserts or updates to the column are not validated against the constraint conditions. DEFAULT, PRIMARY KEY, and UNIQUE constraints cannot be disabled.
The second statement in the given context is redundant if run immediately after the creation of the constraint (with out without WITH CHECK, creation of the foreign key constraint with ADD CONSTRAINT FOREIGN KEY will do the WITH CHECK immediately by default).
The second statement is used to reenable constraint checking
ALTER TABLE [nameOfMyTable] CHECK CONSTRAINT [nameOfMyConstraint];
usually after it has been disabled, like so:
ALTER TABLE [nameOfMyTable] NOCHECK CONSTRAINT [nameOfMyConstraint];
GO
Scripting tools often create DDL like this - overkill, although I guess they really want to be sure :)
There is a third flavour, which is to re-check the validity of the constraint, e.g. after doing a Bulk Copy or similar which may have invalidated the constraint (marked it as untrusted). This is done like so:
ALTER TABLE [nameOfMyTable] WITH CHECK CHECK CONSTRAINT [nameOfMyConstraint];
Edit Hopefully this SQLFiddle clears this up?
I am using SQL Server 2005 and I have to relationships going into one table. I had to turn off " Enforce Foreign Key Constraints" because I have 2 relationships going into the same table.
However I want to put cascade delete on.
I thought if I have cascade delete on both of these relationships and if I say deleted something from on of these tables it would cascade and delete into the other table.
However it does not seem to work that way and I am wondering is it because I have the foriegn key constraint off?
If this is the case how can I get around this?
You've gotta have a fk constraint to enforce cascade delete. how sql server know what to delete otherwise?
I'm not clear on why you needed to disable the foreign key constraints in the first place. You can have many relationships to the same table that all enforce referential integrity. However, if you have two relations to the same parent table in the same child table, you can only have cascade update or cascade delete enabled on one of them.
TBH, I cannot think of a situation where I would want a relationship but wouldn't want it enforced. You should always fix the data and enforce the relation so that the data cannot get corrupted.
This is actually a situation where funneling data access through stored procedures helps. If you forced people to only delete through a stored procedure, you could enforce the cascade delete in the procedure without having to enforce in the DRI.
SQL server will not allow multiple cascade paths. To get around this, add 'FOR DELETE' triggers to each additional path.
ALTER TRIGGER [dbo].[trgMyTriggerName] ON [dbo].[tblMyTable] FOR DELETE AS
SET NOCOUNT ON
DELETE FROM tblMySubTable
WHERE MySubTable_Parent_ID IN (SELECT MyTable_ID FROM deleted)
You will still want to add the foreign key, just set 'Enforce Foreign Key Constraint' to No and make your Delete Rule and Update Rule take no action. This allows you to use all the goodness of Foreign Keys (intellisense, Entity framework etc).