Can I check the dependencies of a stored procedure with other database? - sql

Thank you for reading.
Temp_server
- Temp_db1
. Table : Temp_table
. stored procedure (they refer Temp_table of Temp_db1)
- Temp_db2
. stored procedure (they refer Temp_table of Temp_db1)
Assume that:
there is a server (called Temp_server)
there are two databases (called Temp_db1, Temp_db2)
In Temp_db1, there is a Temp_table and some stored procedures that refer to Temp_table.
In this situation, I can view the list of stored procedure which refer to Temp_table.
But, in SSMS, it shows only the stored procedure of Temp_db1. This means, if there is a stored procedure that is saved on Temp_db2 and refers to Temp_table of Temp_db1, it doesn't show up.
Can I view this, too, somehow?

Can I view this, too, somehow?
You can use sys.sql_expression_dependencies
It shows you dependencies in other databases and even other(linked) servers.
Here is an example when it shows up my historical triggers that writes to another database, Storico.
You can see also test_powershell stored procedure that uses xp_cmdshell from master
and sp_write_execution_log procedure that uses loopback server to execute another sp, sp_write_execution_log_lnk.

Related

Loop Through All SSMS Databases without Recreating Stored Procedure

Background Information:
In Python, I might write something like this if I want to apply the same logic to different values in a list.
database_list = ["db_1", "db_2", "db_3"]
for x in range(0,len(database_list),1):
print("the database name is " + database_list[x])
What I am trying to do:
What I am trying to do in SSMS, is pull a list of DB objects for each database. I created a stored procedure to pull exactly what I want, but I have to run it against each database, so 10 databases mean running it 10 times.
My goal is to do this with a T-SQL query instead of Python.
I tried doing something like this:
exec sp_MSforeachdb 'USE ?; EXEC [dbo].[my_stored_procedure]';
The problem with this is, [dbo].[my_stored_procedure] has to exist in every database I want to do this in.
How can I create the stored procedure in 1 database, but execute it for all databases or a list of databases that I choose?
I know what you are trying to do and if it's what I think (you seem reluctant to actually say!) you can do the following:
In the master database, create your procedure. Normally you wouldn't do this, but in this case you must prefix it sp_
use master
go
create procedure sp_testproc as
select top 10 * from sys.tables
go
Now if you run this, it will return tables from the master database.
If you switch context to another database and exec master.dbo.sp_testproc, it will still return tables from the master database.
In master, run
sys.sp_MS_marksystemobject sp_testproc
Now switch context to a different database and exec master.dbo.sp_testproc
It will return tables from the database you are using.
Try creating your sproc in master and naming it with an sp_ prefix:
USE master
GO
CREATE PROCEDURE sp_sproc_name
AS
BEGIN
...
END
GO
-- You *may* need to mark it as a system object
EXEC sys.sp_MS_marksystemobject sp_sprocname
See: https://nickstips.wordpress.com/2010/10/18/sql-making-a-stored-procedure-available-to-all-databases/
It should then be available in all dbs
Create the stored procedure in the Master database with the sp_ prefix, and use dynamic SQL in the stored procedure so it resolves object names relative to the current database, rather than the database which contains the stored procedure.
EG
use master
go
CREATE OR ALTER PROCEDURE [dbo].[sp_getobjects]
AS
exec ('
select *
from [sys].[objects]
where is_ms_shipped = 0
order by type, name
')
go
use AdventureWorks2017
exec sp_getobjects
#LunchBox - it's your single stored procedure (that you create in one database) that is actually going to need to contain the "exec sp_MSforeach ...." command, and instead of the command to be executed being "EXEC ", it will need to be the actual SQL that you were going to put into the stored proc.
Eg. (inside your single stored procedure)
EXEC sp_MSforeachdb 'USE ?; SELECT * FROM <table>; UPDATE <another table> SET ...';
Think of the stored procedure (that you put into one database) as being no different than your Python code file - if you had actually wanted to achieve the same thing in Python, you would have either needed to create the stored proc in each database, or build the SQL statement string in Python and execute it against each database.
I understand what you thought you might be able to achieve with SQL, but stored procedures really don't work the way you were expecting. Even when you're in the context of a different database, but you run EXEC <different_db>.stored_proc, that stored proc ends up running in the context of the database in which it exists (not your context database).
Now, the only one issue you may come up against is that the standard sp_MSforeachdb stored proc has a limit of 2000 characters for the command that can be executed (although, it does have multiple "command" parameters, this may not be practical if you were planning on running a very large code block, perhaps with variables that carry all the way through). If this is something that might impact what you're intending to do, you could do a search online for "sp_MSforeachdb alternatives" - there seem to be a handful that people have created where the command parameter can contain a larger string.

sql server trigger to update another database whenever a sproc is created

Is there a way to update another database with the newly created stored procedure whenever a stored procedure is created in the main database?
For example, i have two databases, DB1 and DB2.
When I create a stored procedure in DB1, i want that same procedure to created in DB2 automatically? Is there a trigger that can do this?
USE [DB1]
CREATE PROCEDURE [dbo].[TestSproc]
..something
AS
BEGIN
...something
END
I know a use [DB2] statement will do the job, but i want this to be done automatically. Any thought?
Thanks for the help!
This might be a bit evil, but in SQL Server you are able to create DDL triggers which fire when you create/alter/drop tables/procedures etc. The syntax to fire when a procedure is created is:
CREATE TRIGGER <proc-name>
ON DATABASE
FOR CREATE_PROCEDURE
AS
--Your code goes here
In a DDL trigger you get access to an object called EVENTDATA. So to get the text of the procedure you created:
SELECT EVENTDATA().value('(/EVENT_INSTANCE/TSQLCommand/CommandText)[1]','nvarchar(max)')
Now all you need to do is keep that value and execute it in your secondary database. So your query becomes something like this, though I leave the code to update the secondary database down to you as I don't know if it's on the same server, linked server etc.:
CREATE TRIGGER sproc_copy
ON DATABASE
FOR CREATE_PROCEDURE
AS
DECLARE #procedureDDL AS NVARCHAR(MAX) = EVENTDATA().value('(/EVENT_INSTANCE/TSQLCommand/CommandText)[1]','nvarchar(max)')
--Do something with #procedureDDL
As this is not tested, there's probably a few gotchas. For example, what happens if you create procedure with full name (CREATE PROC server.database.schema.proc)
No simple solution for this unless you want to execute the same statement twice, once on each target database,
One thing that comes to my mind is that you can Set up Replication and only publish Stored Procedures to your second database which will be the subscriber in this case.
Following is the window where you select which Objects you want to send over to your secondary databases.

Running synchronous commands to between two sql servers

I'm running a stored procedure on server1 from my application. The stored procedure does a bunch of stuff and populate a table on server2 with the result from the procedure.
I'm using linked server to accomplish this.
When the stored procedure is done running the application continues and tries to do some manipulation of the result from the stored procedure.
My problem is that the results from the stored procedure has not been completely inserted into the tables yet, so the manipulation of the tables fails.
So my question is. Is it possible to ensure the insert into on the linked server is done synchronous? I would like to have the stored procedure not return until the tables on the linked server actually is done.
You can use an output parameter of the first procedure. When the table is create on the second server the output parameter value will be return to your application and indicates the operation is ready.
If the things are difficult then this you can try setting a different isolation level of your store procedure:
http://msdn.microsoft.com/en-us/library/ms173763.aspx
I found the reason for this strange behavior. There was a line of code in my stored procedure added during debug that did a select on a temporary mem table before the data in the same table was written to the linked server.
When the select statement was run, the control was given back to my application and at the same time the stored procedure continued running. I guess the stored procedure was running synchronously from the start.

Possible to create a SQL stored procedure for use for all databases

I have a stored procedure, in one database within my SQL server, that sets permissions to all stored procedures at once for that particulat database. Is there a way to create this stored procedure in a way were I can call it easily from any database within the SQL server and if so how do I go about doing such a thing
While the best solution to this specific question of granting execute to all procedures is the one provided by marc_s, the actual question was is there a way to create a single stored procedure and make it available to all databases.
The way to do this is documented at https://nickstips.wordpress.com/2010/10/18/sql-making-a-stored-procedure-available-to-all-databases/:
Create the stored procedure in the master database.
It must be named to start with sp_, e.g. sp_MyCustomProcedure
Execute sys.sp_MS_marksystemobject passing the name of the procedure, e.g. EXEC sys.sp_MS_marksystemobject sp_MyCustomProcedure
Here is a simple example which just selects the name of the current database:
use master
go
create procedure dbo.sp_SelectCurrentDatabaseName as begin
select db_name()
end
go
execute sys.sp_MS_marksystemobject sp_SelectCurrentDatabaseName
go
Calling exec dbo.sp_SelectCurrentDatabaseName on any database will then work.
To mark the procedure as not a system object, there a some nasty hacks suggested at https://social.msdn.microsoft.com/Forums/sqlserver/en-US/793d0add-6fd9-43ea-88aa-c0b3b89b8d70/how-do-i-undo-spmsmarksystemobject?forum=sqltools but it is safest and easiest to just drop and re-create the procedure.
Caveat
Of course creating system procedures like this is breaking the common rule of not naming your own procedures as sp_xxx, due to the possibility of them conflicting with built-in procedures in future versions of SQL Server. Therefore this should be done with care and not just create a load of randomly named procedures which you find useful.
A common simple way to avoid this is to add your own company/personal prefix to the procedure which Microsoft is unlikely to use, e.g. sp_MyCompany_MyCustomProcedure.
I have a stored procedure, in one database within my SQL server, that
sets permissions to all stored procedures at once for that particular
database.
You could archive the same result much easier:
create a new role, e.g. db_executor
CREATE ROLE db_executor
grant that role execute permissions without specifying any objects:
GRANT EXECUTE TO db_executor
This role now has execute permissions on all stored procedures and functions - and it will even get the same permissions for any future stored procedure that you add to your database!
Just assign this role to the users you need and you're done....
Have you tried a 3 or 4 part name?
InstanceName.DatabaseName.dbo.usp_Name
That procedure could in turn reference objects in other databases using the same conventions. So you could parameterize the name of the database to be operated on and use dynamic SQL to generate 4 part names to reference objects such as system tables.

Stored procedure scope: using sp from another database

I hava a stored procedure named PROC_fetchTableInfo (simple select from sys.tables) in a database named
Cust
I would like use this procedure in a another database named
Dept
I tried to execute this sp in this database using command
EXECUTE Cust.dbo.PROC_fetchTableInfo
but as a result I get tables from the database Cust. How to get this procedure to work in database Dept?
A stored procedure is tighly bound to the objects in its code. If Cust.dbo.PROC_fetchTable references a table T, that is stricly the table T in schema dbo in database Cust. You can invoke the procedure from any other place, it will always refer to this table.
If you need to run the same procedure in another table on another database then the best solution, by far, is to have a new procedure: Dept.dbo.PROC_fetxTableInfo. This is better than the alternative of using Dynamic-SQL. While this seems counteruintuitive from a DRY and code reuse perspective, T-SQL is a data access language is not a programming language, leave your C/C# mind set at the door when you enter the database. Just have another procedure in the Dept database.
Your procedure, Cust.dbo.PROC_fetchTableInfo looks at data in the Cust database. Sounds like you need a copy of it in the Dept database.
Alternately (and quite unsatisfactory to me) you can add a parameter that controls which database to query by building the query in the sproc dynamically.
Perhaps you could create it in some "Common" database and call it like EXEC Common..PROC_fetchTableInfo #databaseName='Dept'
This is possible (if you are trying to write some utility function that you can use across all databases). You can create it in the master database, give it a sp_ prefix and mark it as a system object.
use master
go
CREATE PROCEDURE dbo.sp_sys_tables_select
AS
SELECT * FROM sys.tables
GO
EXEC sys.sp_MS_marksystemobject 'dbo.sp_sys_tables_select'
GO
EXEC tempdb.dbo.sp_sys_tables_select
EXEC msdb.dbo.sp_sys_tables_select