I have a project that run some integration tests. The project creates a new database each time and run the tests against this new db. Recently I moved this project to a new server and I'm having some issues when delete data from the db.
I execute the following query:
DELETE FROM TABLE1;
DELETE FROM TABLE2;
DELETE FROM TABLE3;
On the server A everything works as expected, however using server B I'm getting the following error:
The DELETE statement conflicted with the REFERENCE constraint
"FK_....". The conflict occurred in database
"TestDB", table "Table1", column
'...'.
Both servers have the same version of SQL server
Microsoft SQL Server 2012 (SP1) - 11.0.3401.0 (X64)
Jan 9 2014 13:22:15
Copyright (c) Microsoft Corporation
Standard Edition (64-bit) on Windows NT 6.2 <X64> (Build 9200: ) (Hypervisor)
Both Schema and data are the same and DB are created using the same process.
Any Ideas?
Actually, it is possible to have the same schema in both places, and even the same data, and experience different behavior. How? Because constraints (CHECK and FOREIGN KEY) can be disabled. Yup.
To see if the Foreign Key in question is enabled or disabled, just run the the following, making sure to put the name of the FK in question in the WHERE clause:
SELECT *
FROM sys.foreign_keys
WHERE [name] = N'{name_of_FK_in_question}';
Look at the column named is_disabled. I suspect that it is set to 1 on Server A (where everything "works") and is 0 on Server B (where things "don't work"). I put "works" and "don't work" in quotes, because if this is truly the case, then reality is the opposite of what you are experiencing. Meaning, the system with the FK enabled and getting the error is actually working as that is what FKs should do. The system not getting an error is possibly allowing orphaned (i.e. bad) data in.
To enable the FK, run the following:
ALTER TABLE {table_name}
WITH CHECK -- verifies the data currently in the table
CHECK CONSTRAINT [{name_of_FK_in_question}];
Of course, if the bad data is there, you either need to:
Delete the bad data first, or
Specify WITH NOCHECK on the ALTER so that it will accept the bad data:
ALTER TABLE {table_name}
WITH NOCHECK -- accept the bad data aleady there
CHECK CONSTRAINT [{name_of_FK_in_question}];
However, this does not solve the issue 100%. If you run that SELECT query (noted above) again, you should see that the is_disabled field is now set to 0. BUT, if you look at the is_not_trusted field, it will be set to 1. If a constraint is enabled yet not trusted, it will enforce its rule as expected, but the Query Optimizer (Q.O.) will ignore it, which is generally not a great thing as the constraints are actually used not just to enforce data integrity rules, but also as clues for the Q.O. to logically reduce certain steps in some queries (i.e. they sometimes help increase performance). In order to get the constraint to be "trusted", you will have to delete the bad data and verify all constraints on the table via:
ALTER TABLE {table_name}
WITH CHECK -- verifies the data currently in the table
CHECK CONSTRAINT [{name_of_FK_in_question}];
However, if for some reason you need the "bad" data, then you will just have a Foreign Key that enforces data integrity but has no potential for improving performance (which is still much better than having no FK defined :).
For more info, please see the MSDN page for ALTER TABLE.
For the sake of completeness I will also mention that it is possible that on Server A (where there is no error), that the FK is defined with the option ON DELETE CASCADE which auto-deletes and related data prior to removing the row(s) from the table that is being deleted from, while Server B (where there is an error) does not have the ON DELETE action specfied (or is specified as NO ACTION). This, however, is something that should show up when doing a schema compare (unless specifying to ignore the ON DELETE and ON UPDATE actions), whereas whether the constraint is enabled or disabled is more likely to be ignored in a schema compare.
There is a foreign key (named in the error message) which is preventing you from deleting an item from Table1 because it would violate the foreign key (i.e. a there would be a row in the other table which referenced the row that you were about to delete)
The difference between the two databases is going to either be:
The first database didn't have the foreign key
The first database didn't have any rows in the table constrained by the foreign key
To find which table the foreign key is on see the question How can I list all foreign keys referencing a given table in SQL Server?
EXEC sp_fkeys 'TableName'
Like Justin says, either the keys or data isn't the same, if it works for your case, then setting the keys to cascade of delete will remedy this, but you must identify the keys first.
Related
My company has an application with a bunch of database tables that used to use a sequence table to determine the next value to use. Recently, we switched this to using an identity property. The problem is that in order to upgrade a client to the latest version of the software, we have to change about 150 tables to identity. To do this manually, you can right click on a table, choose design, change (Is Identity) to "Yes" and then save the table. From what I understand, in the background, SQL Server exports this to a temporary table, drops the table and then copies everything back into the new table. Clients may have their own unique indexes and possibly other things specific to the client, so making a generic script isn't really an option.
It would be really awesome if there was a stored procedure for scripting this task rather than doing it in the GUI (which takes FOREVER). We made a macro that can go through and do this, but even then, it takes a long time to run and is error prone. Something like: exec sp_change_to_identity 'table_name', 'column name'
Does something like this exist? If not, how would you handle this situation?
Update: This is SQL Server 2008 R2.
This is what SSMS seems to do:
Obtain and Drop all the foreign keys pointing to the original table.
Obtain the Indexes, Triggers, Foreign Keys and Statistics of the original table.
Create a temp_table with the same schema as the original table, with the Identity field.
Insert into temp_table all the rows from the original table (Identity_Insert On).
Drop the original table (this will drop its indexes, triggers, foreign keys and statistics)
Rename temp_table to the original table name
Recreate the foreign keys obtained in (1)
Recreate the objects obtained in (2)
First, I want to talk a little about the Foreign key constraint rule and how helpful it is. Suppose I have two tables, a primary table with the primary column called ID, the other table is the foreign one which also has a primary column called ID. This column in the foreign table refers to the ID column in the primary table. If we don't establish any Foreign key relation/constraint between those tables, we may fall foul of many problems related to integrity.
If we create the foreign key relation for them, any changes to the ID column in primary table will 'auto' reflect to the ID column in the foreign table, changes here can be made by DELETE, UPDATE queries. Moreover, any changes to the ID in the foreign table should be constrained by the ID column in the primary table, for example there shouldn't any new value inserted or updated in the ID column of the foreign table unless it does exist in the ID column of the primary table.
I know that SQLite doesn't support foreign key constraint (with full functions as detailed above) and I have to use TRIGGER to work around this problem. I have used TRIGGER to work around successfully in one way (Any changes to the ID column in the primary table will refect to the ID column in the foreign table) but the reverse way (should throw/raise any error if there is a confict occurs, for example, there are only values 1,2,3 in the ID column of the primary table, but the value 2 in the ID column of the foreign table is updated to 4 -> not exist in the primary table -> should throw error) is not easy. The difficult is SQLite doesn't also support IF statement and RAISERROR function. If these features were supported, I could work around easily.
I wonder how you can use SQLite if it doesn't support some important features? Even working around by using TRIGGER is not easy and I think it's impossible, except that you don't care about the reverse way. (In fact, the reverse way is not really necessary if you set up your SQL queries carefully, but who can make sure? Raising error is a mechanism reminding us to fix and correct and making it work exactly without corrupting data and the bugs can't be invisible.
If you still don't know what I want, I would like to have some last words, my purpose is to achieve the full functionality of the Foreign key constraint which is not supported in SQLite (even you can create such a relationship but it's fake, not real as you can benefit from it in SQL Server, SQL Server Ce, MS Access or MySQL).
Your help would be highly appreciated.
PS: I really like SQLite because it is file-based, easy to deploy, supports large file size (an advantage over SQL Server Ce) but some missing features have made me re-think many times, I'm afraid if going for it, my application may be unreliable and corrupt unpredictably.
To answer the question that you have skillfully hidden in your rant:
SQLite allows the RAISE function inside triggers; because of the lack of control flow statements, this must be used with a SELECT:
CREATE TRIGGER check_that_id_exists_in_parent
BEFORE UPDATE OF id ON child_table
FOR EACH ROW
BEGIN
SELECT RAISE(ABORT, 'parent ID does not exist')
WHERE NOT EXISTS (SELECT 1
FROM parent_table
WHERE id = NEW.id);
END;
I am using Visual Studio 2012, with a SQL database project and running database analysis against this database and it is raising the following warning:
WITH CHECK | NOCHECK OPTION FOR EXISTING DATA CHECK ENFORCEMENT IS IGNORED.
My understanding of the error is that the CHECK and NOCHECK constraints will be ignored for the existing data when the script is run (in each case for me, it is an ALTER TABLE).
My question is thus, why would a check constraint be ignored?
Warning ID number
It seems the warning ID has changed so I am including both below so that it is easily searchable in future.
In Visual Studio 2010 this had the warning ID of: SQL03159
In Visual Studio 2012 this has the warning ID of: SQL70588
Related Information
ALTER TABLE [dbo].[MyTable] CHECK CONSTRAINT [FK_MyTable_SomeCol]
In my case, this occurred in a script I imported that had a structure like this:
CREATE TABLE [dbo].[ELMAH_Error]
(
[ErrorId] UNIQUEIDENTIFIER NOT NULL,
)
GO
ALTER TABLE [dbo].[ELMAH_Error] WITH NOCHECK ADD
CONSTRAINT [PK_ELMAH_Error] PRIMARY KEY NONCLUSTERED ([ErrorId]) ON [PRIMARY]
GO
When I look at the above code, the WITH NOCHECK looks redundant since the table should have only just been created and therefore be empty. So I suspect this code analysis warning is pointing out this redundancy.
It isn't about redundancy, but rather the fact that the project is desired state, or the ideal state of the DDL schema.
When applying the project to an existing database, the process (publish, dacpac deployment, etc) will enforce the check constraints as the delta is applied. The with check and with nocheck are therefore meaningless in the project DDL that defines the table and subsequent constraint(s).
The only place CHECK and NOCHECK are honored are in the pre and post deployment scripts.
EDIT:
If you ever generate a script from a dacpac you will notice things happen in phases.
When it comes to applying new constraints, they are always added WITH NOCHECK. The final phase is applying WITH CHECK to all constraints that need it, AFTER post deployment scripts are run. This allows the maximum amount of customization to occur during the various phases, including the pre and post deployment script phase.
I am working on a pre-existing MS SQL Server database that was not designed very well. Indexes and primary keys were missing in most cases. There were NO foreign key constraints.
I made a local copy of the DB (so as not to work on the live version), and fixed most of the problems. I now want to syncronize my changes to the production server,
but...
Because there were no previous foreign key constraints there are key mismatches in the tables, thousands of them. I have tried a few synchronization tools, but none of them will allow to ignore or resolve FK mismatches. (in SQL Server Management Studio it's called "Check Existing Data On Creation Or Re-Enabling: No")
Is there a way to auto-resolve the discrepancies of the old database?
Try to use SQL DATA COMPARE from red-gate to syncrhonize data.
https://www.red-gate.com/dynamic/downloads/downloadform.aspx?download=sqldatacompare
You can also try SQL compare to syncrhonize structure, before synchronize data if SQL data compare don't work.
SQL compare
What do you mean by "auto-resolve"?
Existing data is "bad" - that is, the constraints you are trying to impose are violated. There is no way to make your data "good" without modifying it. And there is obviously no way to decide automatically how to fix the data.
So, the best thing you could do is to analyze the data, find out how to correct it, do the corrections manually, and then add the constraints.
You could also just delete all the inconsistent rows (probably a bad idea, if you need the data), or force the server to ignore the constraints for existing data (definitely a bad idea).
If you just want to drop the inconsistent data, I'd suggest you to write (or generate, if there're lots of foreing keys) SQL scripts like this:
DELETE a FROM a LEFT JOIN b ON a.b_id = b.id WHERE b.id IS NULL
ALTER TABLE a ADD CONSTRAINT FK_a_b_id FOREIGN KEY (b_id) REFERENCES b (id)
I am trying to sync up the schemas between to different databases. Basically, I ran tasks->Generate Scripts with SQL Server Management Studio (2005) on both databases and am comparing the output with a diff tool.
For some reason, one script adds the constraint WITH CHECK and one WITH NO CHECK, followed by both constraints being re-enabled.
I for the first database I get:
ALTER TABLE [dbo].[Profile] WITH CHECK ADD CONSTRAINT [FK_Profile_OrganizationID] FOREIGN KEY([OrganizationID])
REFERENCES [dbo].[Organization] ([OrganizationID])
GO
ALTER TABLE [dbo].[Profile] CHECK CONSTRAINT [FK_Profile_OrganizationID]
GO
The second database generates as
ALTER TABLE [dbo].[Profile] WITH NOCHECK ADD CONSTRAINT [FK_Profile_OrganizationID] FOREIGN KEY([OrganizationID])
REFERENCES [dbo].[Organization] ([OrganizationID])
GO
ALTER TABLE [dbo].[Profile] CHECK CONSTRAINT [FK_Profile_OrganizationID]
GO
So I have two questions:
Is the end result the same?
(Edit:
It seems that a lot of people are picking up on only the first statement of the two scripts. I am interested in the end result of the entirety of both scripts.)
If the end result is the same, why does Management Studio generate them differently for different databases?
The end result is not the same!
SQL Server will not trust the uniqueness of the FK is it is not checked. This means additional processing is required if you use the column in a query.
Long story short is that you should get SQL Server to check the column so it's considered trusted.
As for why they're different from different servers, check the isnottrusted column in sys.foreign_keys. This may affect what SSMS is generating?
For more of a rant on this, check my other answer that relates to FK & NO CHECK/ CHECK options.
Yes the two scripts are different
WITH CHECK will check existing data against the new constraint.
WITH NOCHECK will not check existing data against the new constraint. This will allow you to have child records without a corresponding parent.
EDIT:
As for why SSMS is doing this I have no idea
Both are SQL Server 2005 servers? As the result is the same, the code generation tool maybe use different routines based in different versions of the product