SQL Server Check/NoCheck difference in generated scripts - sql-server

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

Related

Different behavior in 2 SQL servers

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.

Changing columns to identity (SQL Server)

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)

How to remove ROWGUID designation on a PK column/key

I am attempting to strip a database of its current UID pks (while retaining the column) as part of a conversion process which will use all int keys.
SSMS 2008 (SQL Express 2008) - Database originally created in SQL 2000.
SQL 2008 full also installed if it helps.
A number of the tables have a UID pk which is ROWGUID=yes
It seems the ROWGUID designation is only found in the KEY properties. I can turn it off there but I'd like to do it as part of a script. If I do a SCRIPT TO on the key or the index I don't see anything indicating the column is a rowguid.
SMO still sees the column as a rowguid after the PK is dropped and the key and index no longer shows in SSMS.
I am a TSQL idiot, so feel free to speak slowly and use small words ;-)
Guidance appreciated. TIA
Did you try:
ALTER TABLE dbo.<table>
ALTER COLUMN <column>
DROP ROWGUIDCOL;
If you're going to become proficient with altering tables via script (which is a great idea, since it is source controllable, much more repeatable and far less error-prone than using the UI), I'd bookmark the ALTER TABLE topic in Books Online.

SQL Server Schema Syncronization

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)

SQLSERVER: How to alter an existing table int primary key to become an identity column?

My database has a table with thousands of records. The primary key is an integer. There's a lot of foreign key constraints associated with this column.
I want to change this column to become an identity key. What's the best way to do it? I also need to send this update to our clients installations.
Bonus points for an answer that works in Sql Server 2000.
There's a great feature in SQL Server Management Studio that saved my day.
In SSMS go to Options -> Designers -> Table and Database Designers, check "Auto generate change scripts" and uncheck "Prevent saving changes that require table re-creation".
In object explorer, go to your table and select the column that will get the Identity specification. Right click and select modify. In the Column properties panel, expand the tree "Identity Specification" and change "(Is Identity)" to yes. Now on the upper left size, select the icon "Generate script". Pay attention to the warning messages.
Now you will have a generated script that will drop all your constraints, recreate the table with identity, and recreate the constraints. WOW!
I'll test it and post here my results.
Update: Everything worked fine. I forgot to say in the question that I need the script to reproduce the modification in our clients installations.
In Enterprise Manager, right click the table in table view, select design.
click the left hand side of the column (then, double click identity, in columns underneath, in column properties, turns it on, defaults to auto increment 1
There is no single "ALTER TABLE" DDL for changing an existing column to an identity column. You can only add a new identity column to an existing table.
This can be done in Enterprise Manager but you need to be aware that Sql server is creating a new table and copying you data across in the background. You may have some issues with this. Here is an article that explains this a bit more http://www.mssqltips.com/tip.asp?tip=1397
In your scenario i think you will need a combination of this script and something to disable and reenable your fk's.
If the column is an integer as a part of existing relationships then it is already unique. Therefore you do not have to worry about duplicates! That's one huge hassle avoided already.
You can either issue an ALTER TABLE command to change the column or you can do it with Enterprise Manager.

Resources