Is there a way to drop a User Defined Table type that is already bound to a stored procedure? - sql

I have an user defined table type (UDTT) that is already bound with a stored procedure which uses it as a input parameter. I have made a mistake in UDTT structure but I cannot alter UDTT so when I tried to delete it, SSMS complaints that its bound to store procedure so it cannot be deleted. Is there away to delete my UDTT?
thanks

It is required on the drop, and what I normally do is set myself a template script that follows this execution:
-- Table builds or the type
if object_id(N'dbo.<tablename>') is null
begin <create table chunk> end
-- Proc Drops
-- UDTT Drops
-- UDTT Adds
-- Proc Adds
Then if you ever need to Alter a proc, you just seek it on that script and execute the script again. Since there is no saved data in a procedure, this solves type overlooks as well as recompile options needing processed. I found it to make development as well as testing much more conducive.

There is an easy work around here. I use SSMS, and select
SCRIPT AS > CREATE TO > NEW QUERY EDITOR WINDOW.
This gives a script to create. I then rename the existing data type rather than deleting it. Make whatever changes are needed to the recreate script, and execute.
You can then drop the renamed data type.
Its a bit of a work around, and an alter command would be better, but this does the job.

Related

SQL Server 2017 Doesn't Validate User Function when updating Temp table

This is a crazy one, seems like a bug to me. I changed the signature of a scalar user function to include an additional parameter, and I was trying to refactor my sprocs which call it, and I noticed an issue which I was able to recreate with two test functions.
First, I created a scalar user function called "test_function" which take a single integer parameter. It doesn't matter what the function does for this test.
Then I created a sproc, which has a simple temp table of 1 column value "thevalue"
Then I execute the alter or create update, but without the parameter:
Intellisense correctly indicates that there's a parameter missing in test_function. But here's where the problem occurs, I can still create or alter this sproc without any errors!
However, if I remove the temp table from the equation, and update a variable, I get the expect error when trying to create or alter the sproc:
Is there a possible setting or a way to flag this specific sproc so that the error would occur and the sproc not be altered?

SQL - How to: IF then GO (execute new query) in the same script without dynamic SQL?

In short, I'm managing a bunch of versioned SQL Scripts where one requirement is that they need to be sort of backwards compatible in that the same scripts can be executed multiple times, still guaranteeing the same end result for the latest version. Basically, say we are on version 3. We need to be able to run scripts for versions 1, 2 and 3 over and over, without errors, and still guarantee that the end result is the same complete version 3.
Now this is easy with normal scenarios (just check if column / table / type is right and create / modify if not), but how do you deal with for instance a trigger that's way over 8000 characters long and can't be executed as dynamic SQL? As version 2 is installed, the triggers are dropped, at the end, new ones are created to match v2's datamodel. But if v3 removed one of the columns referred to by the v2 trigger, that trigger will now fail.
I can't make any kind of IF checks to see if our log has v3 scripts, or if the datamodel doesn't match the requirements. I'd hate to make others do manual labor to do something I'm sure can be automated one way or another. So is there any nice gimmick, trick or just something I missed that could help?
Thanks for the help. :)
but how do you deal with for instance a trigger that's way over 8000
characters long and can't be executed as dynamic SQL?
It can be executed using sp_executesql for which size of sql statement is limited only by available database server memory.
You need to check if object exists and create it if you need or delete otherwise.
if object_id(N'your_table_name','U') is null
CREATE TABLE
...
GO
/* add column */
if not exists (select * from sys.columns
where object_id=object_id('TableName','U') and name='ColumnName')
ALTER TABLE TableName
ADD ColumnName
GO
/* creating Stored Procedure */
if object_id(N'ProcedureName','P') is null
EXEC sp_executesql N'CREATE PROCEDURE ProcedureName AS print 1'
GO
ALTER PROCEDURE ProcedureName
AS
/*your actual code here*/
GO
/* and so on */
Object types for object_id function you can see here.

Need to move stored procedure into system stored procedure folder

When I created my stored procedure somehow I managed to place it within the stored procedures folder, however not inside the system stored procedures folder (the system SP folder exists within the stored procedures folder). How do I move it one level down into the system stored procedures folder?
EDIT: After reading the answers below I'm thinking that the problem is how I'm telling my C# program to access the stored procedure. I have this line of code that is throwing an exception, telling me that it cannot find it:
SqlCommand cmd = new SqlCommand("<database_name>.dbo.<stored_procedure_name>.sql", conn);
If anyone can offer any help on how to call the stored procedure properly it would be appreciated. Thx!
You don't, or at the least shouldn't.
This is for system stored procedures, which are built into the RDBMS and used for system functions, like renaming objects or checking users on the server.
Don't think of these as folders like in a file system - they are just organizing your objects based on existing meta-data (Stored procedure or View? System object or User object?)
You can conceivably mark it as a system object, but that's just a terrible idea.
Why do you want to obfuscate your procedure? If you are creating it it's obviously a user procedure and not a system one.
I'm really not sure why you would need to do this, but you can:
exec sp_ms_marksystemobject myprocname
It's undocumented - so I you won't have any support if you try and use it, and it might be removed from a future version of SQL Server.
+1 for #JNK's comment above.
Also, ensure that you've created the stored procedure under the schema you think you did. If you execute a statement like this:
create procedure foobar as ...
the stored procedure foobar gets created under your default schema, which is likely not dbo. You should always create and reference database objects with at least a 2-level, schema-qualified name:
create procedure dbo.foobar ...
create procedure some_schema.foobar ...
lest you shoot yourself in the foot. You should schema-qualify references as well. References like
select * from some_table
exec some_stored_procedure
rather than
select * from dbo.some_table
exec dbo.some_stored_procedure
are resolved by first probing for an object of the desired name and type under your default schema. If found, that is the object used to resolve the reference. If no such object is found, then a probe is made under the schema dbo.
Further, you should not generally give a stored procedure a name that begins with sp_: that further complicates (and slows down) resolution, throwing probes of the master database into the mix.

Using table just after creating it: object does not exist

I have a script in T-SQL that goes like this:
create table TableName (...)
SET IDENTITY INSERT TableName ON
And on second line I get error:
Cannot find the object "TableName" because it does not exist or you do not have permissions.
I execute it from Management Studio 2005. When I put "GO" between these two lines, it's working. But what I would like to acomplish is not to use "GO" because I would like to place this code in my application when it will be finished.
So my question is how to make this work without using "GO" so that I can run it programmatically from my C# application.
Without using GO, programmatically, you would need to make 2 separate database calls.
Run the two scripts one after the other - using two calls from your application.
You should only run the second once the first has successfully run anyway, so you could run the first script and on success run the second script. The table has to have been created before you can use it, which is why you need the GO in management studio.
From the BOL: "SQL Server utilities interpret GO as a signal that they should send the current batch of Transact-SQL statements to SQL Server". Therefore, as Jose Basilio already pointed out, you have to make separate database calls.
If this can help, I was faced with the same problem and I had to write a little (very basic) parser to split every single script in a bunch of mini-script which are sent - one at a time - to the database.
something even better than tpdi's temp table is a variable table. they run lightning fast and are dropped automatically once out of scope.
this is how you make one
declare #TableName table (ColumnName int, ColumnName2 nvarchar(50))
then to insert you just do this
insert into #TableName (ColumnName, ColumnName2)
select 1, 'A'
Consider writing a stored proc that creates a temporary table and does whatever it needs to with that. If you create a real table, your app won't be able to run the script more than once, unless it also drops the table -- in which case, you have exactly the functionality of a temp table.

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