MS SQL Server - What is the value of WITH CHECK in a foreign key constraint? - sql

When I have SQL Server Management Studio generate a table creation script for me, the foreign key constraints are a bit different than how I would write them.
Here is one:
ALTER TABLE [dbo].[GeoBytesCountries]
WITH CHECK
ADD CONSTRAINT [FK_GeoBytesCountries_MapReferenceId]
FOREIGN KEY ([MapReferenceId])
REFERENCES [dbo].[GeoBytesMapReferences] ([MapReferenceId])
GO
ALTER TABLE [dbo].[GeoBytesCountries]
CHECK CONSTRAINT [FK_GeoBytesCountries_MapReferenceId]
GO
I would write this foreign key constraint without "WITH CHECK" and the 2nd "CHECK CONSTRAINT" statement and expect to get the same functionality.
Can someone explain to me the value of the using "WITH CHECK" and a separate "CHECK CONSTRAINT" statement when you are writing a foreign key constraint for a table?
Or is the code below completely / functionally equivalent to the code above?
ALTER TABLE [dbo].[GeoBytesCountries]
ADD CONSTRAINT [FK_GeoBytesCountries_MapReferenceId]
FOREIGN KEY ([MapReferenceId])
REFERENCES [dbo].[GeoBytesMapReferences] ([MapReferenceId])
GO

The way I see it, the two step approach allows you to at least keep more "bad" data from getting in assuming the with check part fails. That is, your constraint will exist and apply to DML from that point forward, but you may have to do some cleanup on your existing data to make it a trusted constraint.

Related

Inserting new record and skip if foreign key conflict in sql server 2008 R2

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

Generating Create script for existing foreign key through SSMS

While generating the Create DB script for the existing Foreign Key constraint through SSMS, we could able to see two set of alter statements. one with NOCHECK ADD and another with CHECK.
ALTER TABLE [dbo].[claim] WITH NOCHECK ADD CONSTRAINT [FK_CLAIM_COPCID]
FOREIGN KEY([copcid])
REFERENCES [dbo].[copc] ([CopcId])
GO
ALTER TABLE [dbo].[claim] CHECK CONSTRAINT [FK_CLAIM_COPCID]
GO
Why we are getting two set of scripts to create a new Constraint?.
The first alter statement is creating a constraint and instructing that constraint to be added without checking whether the existing rows obey the new constraint.
When you add a constraint without first checking the rows, it will not be fully active until you enable it. That's what the second statement does, it enables the new constraint. If there are rows that break the constraint, you won't be able to enable it.

Difference in SQL syntax for enabling a constraint (SQL Server)

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.

What does second check constraint mean?

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?

Please explain the syntax the SQLServer uses to create a check constraint

When I right click on a default constraint and I ask SQL Server to create a CREATE script for it, it generates the following code:
ALTER TABLE [dbo].[tblEventTurnJudgeStartValues] WITH NOCHECK ADD CONSTRAINT [tblEventTurnJudgeStartValues_ExecutionToggle] CHECK (([ExecutionToggle]=(1) OR [ExecutionToggle]=(0) OR [ExecutionToggle]=(-1)))
GO
ALTER TABLE [dbo].[tblEventTurnJudgeStartValues] CHECK CONSTRAINT [tblEventTurnJudgeStartValues_ExecutionToggle]
For the record, I understand the first ALTER statement but I do not understand what the the second alter statement does. Tried to google the "CHECK CONSTRAINT" phrase but only got hits on the add constraint syntax.
Thanks.
Seth
update
Thanks Joe for your answer. Found this link which helps.
http://blog.sqlauthority.com/2009/11/12/sql-server-disable-check-constraint-enable-check-constraint/
I did not know that you could enable and disable constraints. Cool!
Seth
The first statement creates the constraint, but since it is created with NOCHECK, existing data is not validated at the time of creation.
The second statement simply turns the constraint on and is technically redundant.
Personally, I'd prefer the second statement be written with the WITH CHECK option, which will validate all existing data against the constraint and will prevent the constraint from becoming untrusted.
ALTER TABLE [dbo].[tblEventTurnJudgeStartValues] WITH CHECK CHECK CONSTRAINT [tblEventTurnJudgeStartValues_ExecutionToggle]