You can run the DBCC CHECKCONSTRAINTS
console command to return a list of all constraint violations in a SQL Server database.
This command checks the integrity of a specified constraint or all constraints on a specified table in the current database. It returns any foreign key and CHECK
constraint violations that it finds.
You can use the ALL_CONSTRAINTS
option to check both enabled and disabled constraints. If you omit this, then only enabled constraints are returned (unless you explicitly specify a constraint to check, in which case it will be returned regardless of whether it’s enabled or disabled).
Example 1 – Violated CHECK Constraints
I ran this example against a database that contains some CHECK
constraint violations.
USE Test; DBCC CHECKCONSTRAINTS WITH ALL_CONSTRAINTS;
Result:
+------------------------+-------------------+---------------------------------------------------------+ | Table | Constraint | Where | |------------------------+-------------------+---------------------------------------------------------| | [dbo].[Occupation] | [chkJobTitle] | [JobTitle] = 'Digital Nomad' | | [dbo].[ConstraintTest] | [chkValidEndDate] | [StartDate] = '2020-01-01' AND [EndDate] = '1999-01-01' | | [dbo].[ConstraintTest] | [chkValidEndDate] | [StartDate] = '2021-10-25' AND [EndDate] = '2021-10-24' | +------------------------+-------------------+---------------------------------------------------------+
This shows that I have three constraint violations in my database.
Explanation of the Columns
The three columns return the following information:
- Table
- Name of the table name that contains the constraint violation.
- Constraint
- Name of the constraint that is violated.
- Where
- Column value assignments that identify the row or rows violating the constraint. The value in this column can be used in a
WHERE
clause of aSELECT
statement querying for rows that violate the constraint.
Therefore, thanks to the third column, I can now find (and update) all invalid data.
Find the Invalid Data
So if we look at the first row from my DBCC CHECKCONSTRAINTS
results, we see that we can find the offending data by using [JobTitle] = 'Digital Nomad'
in a WHERE
clause.
Like this:
SELECT * FROM [dbo].[Occupation] WHERE [JobTitle] = 'Digital Nomad';
Result:
+----------------+---------------+ | OccupationId | JobTitle | |----------------+---------------| | 7 | Digital Nomad | +----------------+---------------+
The Constraint Definition
Let’s take a look at the actual definition for the chkJobTitle
constraint:
SELECT Definition FROM sys.check_constraints WHERE name = 'chkJobTitle';
Result:
+-------------------------------+ | Definition | |-------------------------------| | ([JobTitle]<>'Digital Nomad') | +-------------------------------+
This constraint says that the value of the JobTitle column must not be Digital Nomad, yet a digital nomad still managed to get into my database!
Update the Offending Data
You can either update the offending data, delete it, or leave it alone.
In this example I use the same WHERE
clause to update the value:
UPDATE [dbo].[Occupation] SET [JobTitle] = 'Unemployed' WHERE [JobTitle] = 'Digital Nomad';
Now if I run the check again, that record is no longer an issue, and only the other two issues remain:
DBCC CHECKCONSTRAINTS WITH ALL_CONSTRAINTS;
Result:
+------------------------+-------------------+---------------------------------------------------------+ | Table | Constraint | Where | |------------------------+-------------------+---------------------------------------------------------| | [dbo].[ConstraintTest] | [chkValidEndDate] | [StartDate] = '2020-01-01' AND [EndDate] = '1999-01-01' | | [dbo].[ConstraintTest] | [chkValidEndDate] | [StartDate] = '2021-10-25' AND [EndDate] = '2021-10-24' | +------------------------+-------------------+---------------------------------------------------------+
Example 2 – Violated Foreign Key Constraints
In this example I switch to a database that contains a couple of foreign key constraint violations.
USE Music; DBCC CHECKCONSTRAINTS WITH ALL_CONSTRAINTS;
Result:
+----------------+---------------------+--------------------+ | Table | Constraint | Where | |----------------+---------------------+--------------------| | [dbo].[Albums] | [FK_Albums_Artists] | [ArtistId] = '123' | | [dbo].[Albums] | [FK_Albums_Artists] | [ArtistId] = '17' | +----------------+---------------------+--------------------+
In this case, it appears that two rows in the Albums table are referencing an ArtistId that doesn’t exist.
Find the Invalid Data
Again, we can use the Where column to construct our WHERE
clause. This time I’ll add both violations to my WHERE
clause:
SELECT * FROM [dbo].[Albums] WHERE [ArtistId] = '123' OR [ArtistId] = '17';
Result:
+-----------+-------------+---------------+------------+-----------+ | AlbumId | AlbumName | ReleaseDate | ArtistId | GenreId | |-----------+-------------+---------------+------------+-----------| | 21 | Yo Wassup | 2019-03-12 | 17 | 3 | | 22 | Busted | 1901-05-11 | 123 | 3 | +-----------+-------------+---------------+------------+-----------+
So we can now see the two rows that violate the constraint (although it’s only the ArtistId column that violates the constraint).
Check the Primary Key Table
We can confirm the violation by querying the Artists table (i.e. the table that contains the primary key for this foreign key).
So let’s run the same query against the Artists table.
SELECT * FROM [dbo].[Artists] WHERE [ArtistId] = '123' OR [ArtistId] = '17';
Result:
(0 rows affected)
As expected, neither value is in that table.
The foreign key is supposed to prevent this from happening. Either the invalid data entered the database while the foreign key was disabled, or it entered before the foreign key was created. Either way, when creating or enabling a foreign key or CHECK
constraint, you should use WITH CHECK
to specify that all existing data should be checked before enabling the constraint.
Example 3 – Check Only Enabled Constraints
If you only want to check constraints that are currently enabled, remove WITH ALL_CONSTRAINTS
:
USE Test; DBCC CHECKCONSTRAINTS;
Result:
+--------------------+---------------+------------------------------+ | Table | Constraint | Where | |--------------------+---------------+------------------------------| | [dbo].[Occupation] | [chkJobTitle] | [JobTitle] = 'Digital Nomad' | +--------------------+---------------+------------------------------+
So out of the two constraints that were violated, it appears that chkJobTitle is the only one that was enabled.
We can further verify this with the following query:
SELECT name, is_disabled FROM sys.check_constraints WHERE name = 'chkValidEndDate' OR name = 'chkJobTitle';
Result:
+-----------------+---------------+ | name | is_disabled | |-----------------+---------------| | chkJobTitle | 0 | | chkValidEndDate | 1 | +-----------------+---------------+
Example 4 – Check Only Constraints for a Given Table
You can add the name of a table in parentheses if you only want to check the constraints for that table:
USE Test; DBCC CHECKCONSTRAINTS(ConstraintTest) WITH ALL_CONSTRAINTS;
Result:
+------------------------+-------------------+---------------------------------------------------------+ | Table | Constraint | Where | |------------------------+-------------------+---------------------------------------------------------| | [dbo].[ConstraintTest] | [chkValidEndDate] | [StartDate] = '2020-01-01' AND [EndDate] = '1999-01-01' | | [dbo].[ConstraintTest] | [chkValidEndDate] | [StartDate] = '2021-10-25' AND [EndDate] = '2021-10-24' | +------------------------+-------------------+---------------------------------------------------------+
Example 5 – Check a Single Constraint
You can check a single constraint by enclosing its name inside parantheses:
USE Test; DBCC CHECKCONSTRAINTS(chkValidEndDate);
Result:
+------------------------+-------------------+---------------------------------------------------------+ | Table | Constraint | Where | |------------------------+-------------------+---------------------------------------------------------| | [dbo].[ConstraintTest] | [chkValidEndDate] | [StartDate] = '2020-01-01' AND [EndDate] = '1999-01-01' | | [dbo].[ConstraintTest] | [chkValidEndDate] | [StartDate] = '2021-10-25' AND [EndDate] = '2021-10-24' | +------------------------+-------------------+---------------------------------------------------------+
When you specify a single constraint, the WITH ALL_CONSTRAINTS
has no effect:
USE Test; DBCC CHECKCONSTRAINTS(chkValidEndDate) WITH ALL_CONSTRAINTS;
Result:
+------------------------+-------------------+---------------------------------------------------------+ | Table | Constraint | Where | |------------------------+-------------------+---------------------------------------------------------| | [dbo].[ConstraintTest] | [chkValidEndDate] | [StartDate] = '2020-01-01' AND [EndDate] = '1999-01-01' | | [dbo].[ConstraintTest] | [chkValidEndDate] | [StartDate] = '2021-10-25' AND [EndDate] = '2021-10-24' | +------------------------+-------------------+---------------------------------------------------------+