I am trying to write a stored procedure for verifying backups. This is what I have done so far.
I have used master to store the procedure.
USE [master]
GO
CREATE PROCEDURE verifyData #filename nvarchar(225)
AS
RESTORE VERIFYONLY FROM DISK = #filename;
GO
GO
But after I save the procedure and check it again the file changes to
USE [master]
GO
/****** Object: StoredProcedure [dbo].[verifyData] Script Date: 05/10/2021 3:49:53 pm ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [dbo].[verifyData] #filename nvarchar(225)
AS
RESTORE VERIFYONLY FROM DISK = #filename;
Where a red squiggly line is shown [dbo].[verifyData] here
Also when I try to execute the procedure my intellisense is not able to pick the procedure out
Any insights would be helpful
But after I save the procedure and check it again the file changes to [dbo].[verifyData]... Also when I try to execute the procedure my intellisense is not able to pick the procedure out
SQL Server DATABASE contains multiple objects such as tables, views, stored procedures, functions, indexes, triggers. These objects owned by a logical entities named SCHEMA.
Unless specified otherwise, all Transact-SQL references to specific object can be a four-part name in the following format: [server_name].[database_name].[schema_name].object_name. This format called Four Parts Name and you can think about it like a full logical path to the object
A four-part name is in a way equivalent to a full path to a file for example: C:\Program Files\Microsoft SQL Server\MSSQL15.SQL2019\MSSQL\DATA\AdventureWorks2019.mdf
To uniquely identify an object within multi-servers environment, you need all four parts: Server Name (1), Database Name (2), Schema Name (3) and Object Name (4).
But when we are working inside a specific database, then we usually uses a two-part name (or two parts "path" if you want), which include the SHEMA and the name of the OBHECT. For example: CREATE PROCEDURE MySchemaName.MySP, or SELECT ColA FROM MySchemaName.MyTableName
A two-part name is in a way equivalent to a relative path to a file. for example if we are in the folder: C:\Program Files\Microsoft SQL Server\MSSQL15.SQL2019\MSSQL\ Then as can use only the relative path to the file DATA\AdventureWorks2019.mdf
Unfortunately most people are lazy (or do not know well) and therefore they are using the name of the object without the name of the SCHEMA, just you did when you created the Stored Procedure. This is not well formatted code!
When you create an object without explicitly using the SCHEMA name (as you did), then SQL Server uses the default schema as the owner of that object, which is [dbo]
But after I save the procedure and check it again the file changes to [dbo].[verifyData]
Off-topic by HIGHLY important! (1) We do not save object but CREATE objects. (2) This is NOT a file but a Stored Procedure.
Note! you must start use the correct phrases if you want to understand.
The answer is simple:
The server uses the right format which is two-part name [dbo].[verifyData] - Name of the default schema, which own the stored procedure + The name of the stored procedure
when I try to execute the procedure my intellisense is not able to pick the procedure
This happens since you did not started with the SCHEMA name. Start to type the name of the SCHEMA and the intellisense should find the SCHEMA name. Next you add dot . and start to type the stored procedure name and the intellisense should find that stored procedure under the SCHEMA
In summary
(1) You should always use at least two-part name (even if most us do not do it)
(2) You can and you should CREATE new SCHEMA and group your objects in the database in a logical groups. To create new SCHEMA you can use: CREATE SCHEMA [Customer]. For more information and option when you CREATE a SCHEMA, check this link.
Related
I encountered a strange problem today.... I did an sp_helptext on a stored procedure but the stored procedure name in the CREATE PROCEDURE statement (in the result) did not correspond to the name I used in the sp_helptext statement (see screenshot below). I tried selecting from the sys.all_sql_modules and also OBJECT_DEFINITION but it gave the same result.
In my example below I used InvIRCode_GetByInvIRID but the result gave me InvIRCode_GetListByInvIRID
I did a bit of research and it seems it is a known SQL Server bug and happens when a stored procedure was renamed.
My question is this: How can I get the correct source code for a stored procedure?
The interesting thing is that when I right-click on the sp in the Object Explorer of SQL Server Management Studio and select to script the procedure to a new window, it does give the correct code.
Note this warning message is returned by sp_rename:
Caution: Changing any part of an object name could break scripts and stored procedures.
The text in the catalog views is not changed by sp_rename. The proc name will be corrected when you script the proc via SSMS or SMO. You can alter (or drop/create) modules using that script to fix the text in the catalog views after a rename.
If you run the following in sql server...
CREATE SCHEMA [cp]
GO
CREATE TABLE [cp].[TestIt](
[ID] [int] NULL
) ON [PRIMARY]
GO
CREATE PROCEDURE cp.ProcSub
AS
BEGIN
Print 'Proc Sub'
END
GO
CREATE PROCEDURE cp.ProcMain
AS
BEGIN
Print 'Proc Main'
EXEC ProcSub
END
GO
CREATE PROCEDURE cp.ProcMain2
AS
BEGIN
Print 'Proc Main2'
SELECT * FROM TestIt
END
GO
exec cp.ProcMain2
GO
exec cp.ProcMain
GO
You get the error
Could not find stored procedure 'ProcSub'
Which makes it impossible to compartmentalize procedures into a schema without hard coding the schema into the execution call. Is this by design or a bug as doing a select on tables looks in the procedures schema first.
If anyone has a work around I'd be interested to hear it, although the idea is that I can give a developer two stored procedures which call each other and can put into whatever schema they like in 'their' database that they can run for the purpose of being a utility that looks at the objects of another given schema in the same database.
I have looked to see if I might be able to get round it with Synonyms but they seem to have the same problem associated with them.
This is by design, because the default schema is not set for the user calling the procedure.
When schema is not specified in the query, sql server will try the default schema first and then the dbo (if different) schema. So you need to set the default schema or make your procedure creation using fully qualified names.
Check out:
Beginning with SQL Server 2005, each user has a default schema. The
default schema can be set and changed by using the DEFAULT_SCHEMA
option of CREATE USER or ALTER USER. If DEFAULT_SCHEMA is left
undefined, the database user will have dbo as its default schema.
https://technet.microsoft.com/en-us/library/ms190387%28v=sql.105%29.aspx
The MS SQL Server version in question is 8.
In the context of database other than master if I call stored procedures from master database, for some of them I must append master.. prefix (otherwise I get Could not find stored procedure 'procname' error), for some of them I don't.
For example, I can call --
EXEC sp_addlogin 'user' 'pass';
-- and it works, but --
EXEC xp_cmdshell 'command';
-- doesn't. I have to prepend master.. for it to work --
EXEC master..xp_cmdshell 'command';
I may be wrong here but I observed that one have to add master.. to only those stored procedures that start with xp_ (as opposed to sp_).
Why do I have to call some of them with master.. prepended while some of them can be called without?
Procedures in the master database whose name begin with sp_ can be called in any other user database without having to add the master.. prefix. Since procedures beginning with xp_ don't follow that rule, you still need to add the master.. prefix when calling them.
See this link for more information.
The xp_ stands for extended stored procedures. They are stored in the master database.
The sp_ are for "special". They are Microsoft-shipped procedures that exist in every database. You can see them in the Object Explorer by going (Database Name) > Programmability > Stored Procedures > System Stored Procedures. Because they are in the same database as your query, you don't need to add master..
As a side note, it would be wise to NOT name your own stored procedures with sp_.... See explanation here.
I have a stored procedure in SQL Server 2008 such as:
CREATE PROCEDURE [dbo].[test]
AS
BEGIN
SET NOCOUNT ON;
SELECT user_name();
SELECT SCHEMA_NAME()
SELECT * FROM MyView
END
I have a view named testuser.MyView. I then call the SP using:
exec as user = 'testuser' exec test
This shows the user_name and SCHEMA_NAME are both set to testuser
However I also get a Invalid object name 'MyView'. message, as the SP is still looking up the view name in the dbo schema.
Is there anyway to change how the SP is executed so the MyView object references testuser.MyView without having to use a fully qualified name?
I am trying to use a single set of many stored procedures, on identical table structures in different schemas. I really want to avoid rewriting all the SPs using dynamic SQL, or to create copies of all the SPs each using qualified names.
Unqualified object names are resolved using the module owner's default schema. This behavior can't be changed so you'll need to resort to the other methods you mentioned.
Since you already create separate tables and views for each user with the same structure, why not create stored procedures in the user's schema at the same time?
I have observed the following feature when I rename a stored procedure.
sp_RENAME 'User_Validate', 'sp_UserValidate'
And when I do sp_helptext sp_UserValidate the procedure's name that i see is
CREATE PROCEDURE User_Validate
(#userEmail nvarchar(200),
#userPassword nvarchar(32))....
Why doesn't the name get updated in the stored procedure?
But when I check
select * from sys.procedures
I find the name field being updated? What's the reason behind it? The only logical conclusion I can draw is it's better to drop the procedure and recreate with a new name.
edit 1:
If I do sp_helptext User_Validate it returns "The object 'User_Validate' does not exist in database 'Process' or is invalid for this operation." But when I view the stored procedure the name User_Validate is still there.
Note: I know that renaming stored procedures is not a good practice, the question I asked is out of curiosity.
sp_helptext does not reverse engineer the procedure, it simply shows the original T-SQL batch that created the procedure, including comments and white spaces.
sp_rename is not recommended for renaming stored procedures, views, triggers, and user defined functions
Your conclusion is right, you should drop and re-create it with a new name. The same is stated in BOL - Rename a Stored Procedure
You should also check the dependencies of a stored procedure because renaming a stored procedure may cause dependent objects to fail if they are not updated to match the change
Hope this helps