SQL Studio - "Modify Stored Procedure" Script Errors - ssms

In MS SQL Server Management Studio 2005:
If you have the setting Tools|Options|Scripting|"Include IF NOT EXISTS clause" set to true, modifying a stored procedure will create a strange script that doesn't even work. It looks something like the following: (ellipsis used for brevity)
SET QUOTED_IDENTIFIER ON
GO
IF NOT EXISTS [...]
BEGIN
EXEC dbo.sp_executesql #statement = N'
ALTER procedure [dbo].[p_Procedure]
[...]
'
END
This obviously doesn't work because the only way the ALTER statement is called, is if the stored procedure DOESN'T exist.
The question is thus: is there any way of changing this generated code? A template out there somewhere (this doesn't seem to be related to the build in Templating tools)?
(A slight explanation for this behavior: scripting a CREATE statement generates the same code in which the IF NOT EXISTS makes more sense)

There are some issues on this topic on MS-feedback site.
Here are one:
https://connect.microsoft.com/SQLServer/feedback/ViewFeedback.aspx?FeedbackID=260519
Here are one comment on that issue (from the bottom of the page linked above):
In SQL2000, the approach was If
exists, DROP followed by a CREATE.
This worekd flawlessly and covered all
cases. It wored so well that we built
our deployment off of this scripting
model. Since SQl2005 entered our
world, we have had manual, cumbersome
workarounds to replace the automated
scripting that was lost in the move to
SQL2000.
Please do readd the If exists, DROP
followed by a CREATE approac. It was
great the way

Related

How to tell if ALTER PROCEDURE worked?

I'm pretty new to SQL and SQL Server. I'm trying to run an ALTER PROCEDURE query from a .sql file called through C# code. Before I move on to making sure my query does what it's supposed to do, I want to verify that my ALTER PROCEDURE query actually altered the procedure, but I don't know how to verify that.
For example, in SQL Server, I can see where the stored procedure I'm trying to edit lives, in:
- database-name
- Programmability/
- Stored Procedures/
- dbo.MyStoredProcedure
If my ALTER TABLE query worked correctly, would I be able to see my procedure code here, or would I check somewhere else? Or am I thinking about this the wrong way?
Generally, we rely on error and exception messages to tell us when something like this has not worked. However, I suppose that it might be possible that the procedure Alter-ed was not the one that was intended (implying bugs in the name/path/call construction, of course).
In that case, you can get the current text of any SQL Module (Procedure, View, Trigger, etc., anything script-baseD) from the sys.sql_modules table:
SELECT definition FROM sys.sql_modules
WHERE object_id=OBJECT_ID('dbo.UserSamples_Insert')
You should note that usually when something like this happens without an error message it is because either:
You are executing in the wrong database (like PROD when you meant to be in DEV or vice-versa), or
You are not using the correct Schema (because you can make and use schemas other than 'dbo').
Wait, you say ALTER PROCEDURE twice, but then the third time you say ALTER TABLE. Which is it? I ask because unlike almost every other SQL object, tables are not script-based and their definition cannot be found in any of the Sql script repositories like sys.sql_modules. I actually use either SMO (from a client) or a tool that #SeanLange wrote years ago for that (from the server itself).

Using MSDB stored procedures in application's database stored procedure

This seems like it would be trivial, but I have not been able to come up with a solution to this small problem.
I am attempting to create a stored procedure in my application's database. This stored procedure just executes a job that has been set up in the SSMS on the same server (seemed to be the only way to programmatically execute these jobs).
The simple code is shown below:
USE ApplicationsDatabase
GO
CREATE PROCEDURE [dbo].[procedure]
AS
BEGIN
EXEC dbo.sp_start_job N'Nightly Download'
END
When ran as is, the procedure technically gets created but cannot be executed due to it not being able to find the 'sp_start_job' since it is using the ApplicationsDatabase. If I try to create the procedure again (after deleting previously created) but updating the USE to MSDB, it tries to add it to that system database for which I do not have permissions to do. Finally, I attempted to keep the original create statement but added the USE MSDB within the procedure (just to use the 'sp_start_job' procedure), but it would error saying USE statements cannot be placed within procedures.
After pondering on the issue for a little (I'm obviously no SQL database expert), I could not come up with a solution and decided to solicit the advice of my peers. Any help would be greatly appreciated, thanks!
You will have to fully qualify the path to the procedure. Of course, you can only execute this is the application has permissions.
Try this:
USE ApplicationsDatabase
GO
CREATE PROCEDURE [dbo].[procedure]
AS
BEGIN
EXEC msdb.dbo.sp_start_job N'Nightly Download'
END

Stored Procedure gives Cannot find object... error in SSIS, but works fine in SSMS

I am trying to build an SSIS package that dynamically rebuilds the indexes for all the tables in my database. The general idea is that the package will make sure that the table is not being update and then execute a stored procedure that drops the old index, if it exists, and then recreates it. The logic behind the package seems to be sound. The problem that I am having is when I execute the package I keep getting the error:
Cannot find object...because it does not exist or you do not have permission...
The index existing should be irrelevant due to the IF EXISTS part.
The procedure looks like this:
REFERENCE_NAME AS VARCHAR(50),
COLUMN_NAME AS VARCHAR(50),
INDEX_NAME AS VARCHAR(50)
AS
BEGIN
SET NOCOUNT ON;
DECLARE #sql NVARCHAR(MAX)
SET #sql = 'IF EXISTS (SELECT name FROM sysindexes WHERE name = '+CHAR(39)+#INDEX_NAME+CHAR(39)+') '+
'DROP INDEX '+#INDEX_NAME+' ON '+#REFERENCE_NAME+' '+
'CREATE INDEX '+#INDEX_NAME+' ON '+#REFERENCE_NAME+'('+#COLUMN_NAME+') ON [INDEX]'
EXEC sp_executesql #sql
END
GO
I am able to execute the procedure through SSMS just fine, no error and it builds the index. When I execute the package in SSIS it errors out the minute it gets to the task that executes the stored procedure. I have made sure that SSIS is passing the variables to the execute SQL task and I have verified that I have db_ddladmin rights. Outside of that I am at a loss and have been beating my head against the wall for a day and a half on this.
Is there something I am missing, some permissions I need to request, or some work around for the issue?
Any information would be much appreciated.
Bartover, its definitely not looking at the wrong database. I have checked that the proc is there and the only connection on the package is to that specific database. Yes, I am executing the package manually with Visual Studios 2010 Shell Data Tools.
Sorrel, I tried your idea of a sanity check on the #sql statement on the drop, on both the drop and create, and on whole #sql statement, no joy.
Gnackenson, I had that same thought, but the connection authentication method is set to Windows Authentication, same as ssms. Do you have any ideas as to why it might use different permissions?
It looks like IF EXISTS is being ignored by SSIS SQL Task. To fix my problem, I altered my SQL tasks from DROP - CREATE to DISABLE - ENABLE.

SQL Server : update table tries to drop nonexistent triggers

I am using Microsoft SQL Server 2008 R2 (SP2). I am not using SQL Server Management Studio. I am using a simple webpage with a textarea for a query window that I built myself in PHP, so all I am doing are SQL commands -- no GUI stuff. Never had problems with it before, and I don't think the problems I'm having now are because of my PHP. Anyway, I would most appreciate answers in SQL code rather than answers that recommend I right-click the table name in Management Studio, if you get my drift.
Leading up to the problem...
I used to have three triggers on table dbo.MyOldTableName:
trgOldUpdate1, trgOldUpdate2, and trgOldInsert
I renamed the table using the following code:
EXEC sp_rename 'dbo.MyOldTableName', 'MyNewTableName';
I then dropped those three old triggers and created the following three new triggers (which do the same thing but point to the new table and have new names):
trgNewUpdate1, trgNewUpdate2, and trgNewInsert
I ran this SQL and saw only the new triggers:
SELECT
referencing_schema_name,
referencing_entity_name,
referencing_id,
referencing_class_desc,
is_caller_dependent
FROM
sys.dm_sql_referencing_entities ('dbo.MyOldTableName', 'OBJECT');
I ran this SQL and the old triggers are not there:
SELECT * FROM sys.triggers;
Now all of that above information is simply background. Here is the actual problem. I ran a simple update command (like this SQL):
UPDATE [dbo].[MyNewTableName] SET ColumnName = ColumnName;
...and got these error messages:
Cannot drop the trigger 'dbo.trgOldUpdate2', because it does not exist or you do not have permission.
Cannot drop the trigger 'dbo.trgOldUpdate1', because it does not exist or you do not have permission.
Cannot drop the trigger 'dbo.trgOldUpdate1', because it does not exist or you do not have permission.
Cannot drop the trigger 'dbo.trgOldUpdate2', because it does not exist or you do not have permission.
First, why is SQL Server trying to drop triggers on a simple update command (And before you ask, no, the trigger code itself never drops anything at all)?
Second, why is SQL Server looking for triggers that don't exist?
Third and most important, how do I stop this from happening?
Many thanks in advance for your clear, concise, and self-contained answers! (Hey, a guy can dream, can't he?)
My guess is that there was an error in the trigger DROP/CREATE script such that the DROP statements of the old triggers were inadvertently included in in one of the update triggers. Check the new triggers to see if that is the case:
EXEC sp_helptext N'trgNewUpdate1';
EXEC sp_helptext N'trgNewUpdate2';

DROP...CREATE vs ALTER

When it comes to creating stored procedures, views, functions, etc., is it better to do a DROP...CREATE or an ALTER on the object?
I've seen numerous "standards" documents stating to do a DROP...CREATE, but I've seen numerous comments and arguments advocating for the ALTER method.
The ALTER method preserves security, while I've heard that the DROP...CREATE method forces a recompile on the entire SP the first time it's executed instead of just a a statement level recompile.
Can someone please tell me if there are other advantages / disadvantages to using one over the other?
ALTER will also force a recompile of the entire procedure. Statement level recompile applies to statements inside procedures, eg. a single SELECT, that are recompiled because the underlying tables changes, w/o any change to the procedure. It wouldn't even be possible to selectively recompile just certain statements on ALTER procedure, in order to understand what changed in the SQL text after an ALTER procedure the server would have to ... compile it.
For all objects ALTER is always better because it preserves all security, all extended properties, all dependencies and all constraints.
This is how we do it:
if object_id('YourSP') is null
exec ('create procedure dbo.YourSP as select 1')
go
alter procedure dbo.YourSP
as
...
The code creates a "stub" stored procedure if it doesn't exist yet, otherwise it does an alter. In this way any existing permissions on the procedure are preserved, even if you execute the script repeatedly.
Starting with SQL Server 2016 SP1, you now have the option to use CREATE OR ALTER syntax for stored procedures, functions, triggers, and views. See CREATE OR ALTER – another great language enhancement in SQL Server 2016 SP1 on the SQL Server Database Engine Blog. For example:
CREATE OR ALTER PROCEDURE dbo.MyProc
AS
BEGIN
SELECT * FROM dbo.MyTable
END;
Altering is generally better. If you drop and create, you can lose the permissions associated with that object.
If you have a function/stored proc that is called very frequently from a website for example, it can cause problems.
The stored proc will be dropped for a few milliseconds/seconds, and during that time, all queries will fail.
If you do an alter, you don't have this problem.
The templates for newly created stored proc are usually this form:
IF EXISTS (SELECT * FROM sysobjects WHERE type = 'P' AND name = '<name>')
BEGIN
DROP PROCEDURE <name>
END
GO
CREATE PROCEDURE <name>
......
However, the opposite is better, imo:
If the storedproc/function/etc doesn't exist, create it with a dummy select statement. Then, the alter will always work - it will never be dropped.
We have a stored proc for that, so our stored procs/functions usually like this:
EXEC Utils.pAssureExistance 'Schema.pStoredProc'
GO
ALTER PROCECURE Schema.pStoredProc
...
and we use the same stored proc for functions:
EXEC Utils.pAssureExistance 'Schema.fFunction'
GO
ALTER FUNCTION Schema.fFunction
...
In Utils.pAssureExistance we do a IF and look at the first character after the ".": If it's a "f", we create a dummy fonction, if it's "p", we create a dummy stored proc.
Be careful though, if you create a dummy scalar function, and your ALTER is on a table-valued function, the ALTER FUNCTION will fail, saying it's not compatible.
Again, Utils.pAssureExistance can be handy, with an additional optional parameter
EXEC Utils.pAssureExistance 'Schema.fFunction', 'TableValuedFunction'
will create a dummy table-valued function,
Additionaly, I might be wrong, but I think if you do a drop procedure and a query is currently using the stored proc, it will fail.
However, an alter procedure will wait for all queries to stop using the stored proc, and then alter it. If the queries are "locking" the stored proc for too long (say a couple seconds), the ALTER will stop waiting for the lock, and alter the stored proc anyway: the queries using the stored proc will probably fail at that point.
DROP generally loses permissions AND any extended properties.
On some UDFs, ALTER will also lose extended properties (definitely on SQL Server 2005 multi-statement table-valued functions).
I typically do not DROP and CREATE unless I'm also recreating those things (or know I want to lose them).
I don't know if it's possible to make such blanket comment and say "ALTER is better". I think it all depends on the situation. If you require this sort of granular permissioning down to the procedure level, you probably should handle this in a separate procedure. There are benefits to having to drop and recreate. It cleans out existing security and resets it what's predictable.
I've always preferred using drop/recreate. I've also found it easier to store them in source control. Instead of doing .... if exists do alter and if not exists do create.
With that said... if you know what you're doing... I don't think it matters too much.
If you perform a DROP, and then use a CREATE, you have almost the
same effect as using an ALTER VIEW statement. The problem is that you need to entirely re-establish your permissions on who can and can’t use the view. ALTER retains any dependency information and set permissions.
You've asked a question specifically relating to DB objects that do not contain any data, and theoretically should not be changed that often.
Its likely you may need to edit these objects but not every 5 minutes. Because of this I think you've already hit the hammer on the head - permissions.
Short answer, not really an issue, so long as permissions are not an issue
We used to use alter while we were working in development either creating new functionality or modifying the functionality. When we were done with our development and testing we would then do a drop and create. This modifys the date/time stamp on the procs so you can sort them by date/time.
It also allowed us to see what was bundeled by date for each deliverable we sent out.
Add with a drop if exists is better because if you have multiple environments when you move the script to QA or test or prod you don't know if the script already exists in that environment. By adding an drop (if it already exists) and and then add you will be covered regardless if it exists or not. You then have to reapply permissions but its better then hearing your install script error-ed out.
From a usability point of view a drop and create is better than a alter. Alter will fail in a database that doesn't contain that object, but having an IF EXISTS DROP and then a CREATE will work in a database with the object already in existence or in a database where the object doesn't exist. In Oracle and PostgreSQL you normally create functions and procedures with the statement CREATE OR REPLACE that does the same as a SQL SERVER IF EXISTS DROP and then a CREATE. It would be nice if SQL Server picked up this small but very handy syntax.
This is how I would do it. Put all this in one script for a given object.
IF EXISTS ( SELECT 1
FROM information_schema.routines
WHERE routine_schema = 'dbo'
AND routine_name = '<PROCNAME'
AND routine_type = 'PROCEDURE' )
BEGIN
DROP PROCEDURE <PROCNAME>
END
GO
CREATE PROCEDURE <PROCNAME>
AS
BEGIN
END
GO
GRANT EXECUTE ON <PROCNAME> TO <ROLE>
GO