how to handle db schema updates when using schemabinding and updating often - sql-server

I'm using a MS SQL Server db and use plenty of views (for use with an O/R mapper). A little annoyance is that I'd like to
use schema binding
update with scripts (to deploy on servers and put in a source control system)
but run into the issue that whenever I want to e.g. add a column to a table, I have to first drop all views that reference that table, update the table, and then recreate the views, even if the views wouldn't need to be updated otherwise. This makes my update scripts a lot longer and also, looking the diffs in the source control system, it is harder to see what the actual relevant change was.
Is there a better way to handle this?
I need to still be able to use simple and source-controllable sql updates. A code generator like is included in SQL Server Management Studio would be helpful, but I had issues with SQL Server Management Studio in that it tends to create code that does not specify the names for some indices or (default) constraints. But I want to have identical dbs when I run my scripts on different systems, including the names of all contraints etc, so that I don't have to jump through loops when updating those constraints later.
So perhaps a smarter SQL code generator would a solution?
My workflow now is:
type the alter table statement in query editor
check if I get an error statement like "cannot ALTER 'XXX' because it is being referenced by object 'YYY'."
use SQL Server Managment Studio to script me create code for the referenced object
insert a drop statement before the alter statement and create statement after
check if the drop statement creates error and repeat
this annoys me, but perhaps I simply have to live with it if I want to continue using schemabinding and script updates...

You can at least eliminate the "check if I get an error" step by querying a few dynamic managment functions and system views to find your dependencies. This article gives a decent explanation of how to do that. Beyond that, I think you're right, you can't have your cake and eat it too with schema-binding.
Also keep in mind that dropping/creating views will cause you to lose any permissions that were granted on those objects, so those permissions should be included in your scripts as well.

Related

How to run raw SQL to deploy database changes

We intend to create DACPAC files using SQL database projects and distribute them automatically to several environments, DEV/QA/PROD, using Azure Pipeline. I can make changes to the schema for a table, view, function, or procedure, but I'm not sure how we can update specific data in a table. I am sure this is very common use case but unfortunately I am having hard time implementing it.
Any idea how can I automate creating/updating/deleting a row for a table?
E.g.: update myTable set myColumn = 5 where someColumn = 'condition'
In your database project you can add a Post Deployment Script
Do not. Seriously. I found DACPAC always to be WAY too limiting for serious operations. Look how the SQL is generated and - realize how little control you have.
The standard approach is to have deployment scripts that you generate and that do the changes in the database, plus a table in the db tracking which have executed (possibly with a checksum so you do not need t change the name to update them).
You can easily generate them partially by schema compare (and then generate the change script), but those also allow you to do things like data scrubbing and multi step transformations that DACPAC by design cannot efficiently and easily do.
There are plenty of frameworks for this around. They generally belong in the category of developer tools.

Generate static SQL scripts for SQL objects instead of dynamic SQL when object existence check is turned ON

I have kept "Check for object existence" option turned ON in my SQL Server Mgmt Studio, because I need SQL Server to automatically include "IF EXISTS" statements before dropping and recreating the objects.
Now, whenever I right-click and try to generate "Create and Drop scripts" for any objects, it puts the whole CREATE statement as a dynamic SQL which I think is a pure mess and more prone to errors.
Is there any option to make SSMS generating static SQL scripts when the object existence check is turned on?
I am using SSMS 2012.
If I understand you correctly, this is the correct / best approach...
The problem is, that there is no DROP_AND_CREATE statement in T-SQL. Many people use something like
IF EXISTS(SELECT 1 FROM INFORMATION_SCHEMA.ROUTINES WHERE ROUTINE_NAME='SomeFunction')
DROP FUNCTION dbo.SomeFunction;
GO
CREATE FUNCTION dbo.SomeFunction...
But this is problematic, if there are dependencies like a CONSTRAINT or a GRANT or other...
It is easier to use a check like above and decide if you create the CREATE statement or if you change the first word to ALTER dynamically. You cannot place both statements in some kind of conditional workflow, as it has to be the first in batch.
... pure mess and more prone to errors
Especially with a generated statement I would not expect errors... You are right, that this isn't pretty, but many code generators do not produce pretty code. That doesn't really matter...

Name clash with sys.sysusers system view in SQL Server

(Note that this was on SQL Server 2008, but I have a colleague who reports the same issue on SQL Server 2014.)
I'm using a framework that supports multiple database back-ends, and our application has a table called sysUsers, which works fine in MySQL.
We now need to install it on SQLServer and it appears that this name conflicts with a built-in system view. The system view is sys.sysusers and the application table is dbo.sysUsers.
I am aware that the case difference is irrelevant to SQL Server, however the schema seems to be being ignored for some reason.
SELECT * FROM sys.sysusers; returns records from sys.sysusers. This is wholly as expected.
SELECT * FROM sysUsers; returns records from sys.sysusers. This is surprising (I would have thought the local schema would take precedence) but perhaps explicable.
However, SELECT * FROM dbo.sysUsers; still returns records from sys.sysusers. This seems just plain wrong as I am explicitly selecting the dbo schema.
I haven't found anything in the MS documentation that says these names are reserved.
I have tried renaming the table and hacking the code to use a different name, and everything works (i.e. this is nothing to do with the SQLServer integration within the application) and the same results are seen when running the queries from the management console directly. Therefore this appears to definitely be an issue with the conflicting table name and not a middle-ware error or syntax difference.
If this table name is reserved, why does MSSMS allow me to create it? If it is not reserved, why does it not let me query it?
And how can I work round the problem without requiring application updates (as these would be a migration headache for other deployments).
There are at least three workarounds, but none guarantee that no code has to be rewritten (except the one that's horribly unsafe):
Use a case-sensitive collation when creating your database (CREATE DATABASE Foo COLLATE Latin1_General_CS_AS). In this case, sysUsers will be a different object from sysusers, in all circumstances. You can set a case-insensitive collation immediately after creating the database so your data doesn't end up case-sensitive, as this is probably not what the end users want. Obviously this won't work if your application is actually relying on case-insensitive object names, unless you rewrite your queries carefully. Note that this means that all database objects, even those created afterwards, will have case-sensitive names, as this is embedded in the system tables on creation and can't be changed afterwards.
Use a schema other than dbo. The system table mapping occurs only for that scheme, not any others. If your application uses its own schema exclusively, any sysusers you create in that will not be aliased to sys.sysusers. (This isn't documented anywhere, but it is how it works.) Note that in order for this to work, you must always specify the schema explicitly even when it is the default schema for your user, otherwise you will again get the system table (I'd consider this a bug, but it's probably a necessity because of the way old scripts will assume sysusers resolves anywhere).
Enable the Dedicated Administrator Connection, restart SQL Server in single user mode, switch the mssqlsystemresource database to READ_WRITE and DROP VIEW sysusers. This will remove sys.sysusers from all databases. Doing this will void your warranty, it will cause Microsoft Support to laugh at you if you come crying to them, it may make installing future Service Packs and updates impossible and is emphatically not recommended, but I'm mentioning it anyway, for science. No code anywhere should be using this view, but, you know, I'm not an engineer working on SQL Server itself.
Note that lowering the compatibility level is not a workaround, which I mention for completeness. This has no effect on how these table names are resolved, even if it was a desirable approach (which it's not).
I consider the change made in SQL Server 2012 to ignore the dbo qualifier and resolve to these old, deprecated names anyway a mistake and if it were up to me I'd at least make it possible to opt out of this behavior with a trace flag, but it's not up to me. You could consider opening up an issue on Microsoft Connect for it, because the current behavior makes it needlessly complicated for RDBMS-agnostic code to run.

Sql server ide for refactoring

Is there an IDE for SQL Server that includes refactoring?
For an example, if I have a composite primary key on a table and I change it, sql management studio will drop all foreign keys referencing to this primary key (it will warn first). Is there a tool that generates the DROP statements for the foreign keys and recreates them?
I would look into the SQLDeveloper product from redgate. They offer some refactoring features in their SQL Prompt product. Also take a look at the SQL Compare tool. Both are worth every penny.
I would recommend looking at the Database project type in VS2010, if you haven't already. It has a lot of features that make DB refactoring easier than working SQL Server Management Studio.
For example it does a lot of build-time validation to make sure your database objects don't reference objects which no longer exist. For example if you rename a column, it will give you build errors for FKs that reference the old column name. Also, it has very handy "compare" feature which compares the DB project scripts & databases, generates a DIFF report, and generates the scripts to move selected changes between the two (either DB project to SQL Server, or vice versa).
I'm not sure it will automatically handle your composite key example -- in other words, when you rename a column it won't fix up all references to that column throughout the project. However, since all of the database objects are kept in scripts within the project, things like column renames are just a search & replace operation. Also if you make a mistake you will get build errors when it validates the database structure. So at least makes it easy to find the places that you need to change.
There are probably more powerful tools out there (I have heard good things about redgate) but the VS2010 support for the Database project type is fairly decent.
The way your objects handle foreign key references is upon creation of the table/constraint. ON DELETE CASCADE would only be one option. You can also have it set to NULL or default.
Unless I am misunderstanding your question, it is not the environment but the object parameters that dictate this.

SQL Server Management Studio - Adding/Moving Columns require drop and re-create?

Why do I get message that the table needs to dropped and re-created when I add/move columns?
I believe this happens after adding foreign key constraints.
What can I do to add new columns without dropping table?
If you're more interested in simply getting SSMS to stop nagging, you can uncheck the "Prevent saving changes that require table re-creation" setting in Options->Designers->Table And Database Designers. The table(s) will still be dropped and re-created, but at least SSMS won't pester you quite as much about it.
(This assumes you're working in an dev/test environment or in a production environment where a brief lapse in the existence of the table won't screw anything up)
Because that's how SQL Server Management Studio does it (sometimes)!
Use TSQL's ALTER TABLE instead:
ALTER TABLE
ADD myCol int NOT NULL
SQL Server (and any other RDBMS, really) doesn't have any notion of "column order" - e.g. if you move columns around, the only way to achieve that new table structure is be issuing a new CREATE TABLE statement. You cannot order your columns any other way - nor should you, really, since in the relational theory, the order of the columns in a tuple is irrelevant.
So the only thing SQL Server Management Studio can do (and has done all along) is:
rename the old table
create the new table in your new layout you wish to have
copy the data over from the old table
drop the old table
The only way to get around this is:
not reordering any columns - only add new columns at the end of your table
use ALTER TABLE SQL statements instead of the interactive table designer for your work
When you edit a table definition in the designer, you are saying "here's what I want the table to look like, now work out what SQL statements to issue to make my wishes come true". This works fine for simple changes, but the software can't read your mind, and sometimes it will try to do things in a more complicated way for safety.
When this happens, I suggest that, instead of just clicking OK, click the "Script" button at the top of the dialog, and let it generate the SQL statements into a query window. You can then edit and simplify the generated code before executing it.
There are bugs in SSMS 2008 R2 (and older) that are useful to know:
when the table data is changed, ерушк rendering in SSMS is autorefreshed by SSMS in its already opened tabs (windows) - one should press Ctrl+R to refresh. The options to force refreshing do not appear in SSMS GUI - through buttons, menus or context-sensitive options (on right-clicking)
when a (table or database) schema is modified, like adding/deleting/removing a column in a table, SSMS does not reflect these changes in already opened tabs(windows) even through Ctrl+R, one should close and reopen tabs(windows)
I reported it few years ago through Microsoft Connect feedback, but bugs were closed due to it is "by design"
Update:
This is strange and irritating to see in desktop product developed during 2 decades, while this (autorefreshing) is being done by most webapplications in any browser

Resources