Is there a way to know what are the tables used by one stored procedure by doing an SQL query?
Best regards, and thanks for the help.
P.S.: I'm using SQL Server 2005.
This article on TechRepublic
Finding dependencies in SQL Server 2005
describes a way to do that:
This tutorial will show how you can
write a procedure that will look up
all of the objects that are dependent
upon other objects.
Here is the code to create the system stored procedure for finding object dependencies:
USE master
GO
CREATE PROCEDURE sp_FindDependencies
(
#ObjectName SYSNAME,
#ObjectType VARCHAR(5) = NULL
)
AS
BEGIN
DECLARE #ObjectID AS BIGINT
SELECT TOP(1) #ObjectID = object_id
FROM sys.objects
WHERE name = #ObjectName
AND type = ISNULL(#ObjectType, type)
SET NOCOUNT ON ;
WITH DependentObjectCTE (DependentObjectID, DependentObjectName, ReferencedObjectName, ReferencedObjectID)
AS
(
SELECT DISTINCT
sd.object_id,
OBJECT_NAME(sd.object_id),
ReferencedObject = OBJECT_NAME(sd.referenced_major_id),
ReferencedObjectID = sd.referenced_major_id
FROM
sys.sql_dependencies sd
JOIN sys.objects so ON sd.referenced_major_id = so.object_id
WHERE
sd.referenced_major_id = #ObjectID
UNION ALL
SELECT
sd.object_id,
OBJECT_NAME(sd.object_id),
OBJECT_NAME(referenced_major_id),
object_id
FROM
sys.sql_dependencies sd
JOIN DependentObjectCTE do ON sd.referenced_major_id = do.DependentObjectID
WHERE
sd.referenced_major_id <> sd.object_id
)
SELECT DISTINCT
DependentObjectName
FROM
DependentObjectCTE c
END
This procedure uses a Common Table
Expression (CTE) with recursion to
walk down the dependency chain to get
to all of the objects that are
dependent on the object passed into
the procedure. The main source of data
comes from the system view
sys.sql_dependencies, which contains
dependency information for all of your
objects in the database.
Try sp_depends, although you should probably recompile the stored procedure to update the statistics in the database.
Look up sp_depends system stored proc.
I think that as long as the stored procedure and the tables are all in the same database then you can right click on the procedure in SSMS and click "View Dependencies". I don't know the query behind the dialog though...
As others indicated you can use the Dependancies stored procedures; however, in my experience and this was back on SQL Server 2000, the depandancies were not always reliable. In some cases they weren't being updated. You can always go to the sysComments table assuming your schema is not encrypted.
declare #crlfSearch varchar(max),#objectSearch varchar(max),#escapeSearch varchar(max)
set #crlfSearch=('%bid' + char(13)+'%')
set #objectSearch='%bid %'
set #escapeSearch ='%[[]Bid]%'
select distinct so.name
from syscomments sc
inner join sysobjects so
on sc.id=so.id
where text like #objectSearch or text like #crlfSearch
or text like #escapesearch
This query looks for three common cases you might have to add some but basically we find where the table name has a space after it, (This helps to limit cases where the table name is part of another table name), Has a return at the end of it, or is escaped within brackets.
Related
I have a script which searches through all the available databases (those I have access to) for a specific text in a procedure.
In my server, there are many databases (in my case about 150 databases), meaning that I get shown the results for all databases eventhough there are no results for most of them (about 90%).
Is there any way to avoid getting these empty result-queries?
You can use below code to check whether stored procedure contains a text in each database. If there are stored procedures in a database only, you will have resultset.
CREATE TABLE ##DatabasesContainingSP(dbname sysname, SPName SYSNAME);
EXECUTE master.sys.sp_MSforeachdb 'USE [?];
INSERT INTO ##DatabasesContainingSP
SELECT DISTINCT
db_name() as dbname, o.name AS Object_Name
FROM sys.sql_modules m
INNER JOIN
sys.objects o
ON m.object_id = o.object_id
WHERE m.definition Like ''%ABC%'';
'
IF EXISTS(SELECT * FROM ##DatabasesContainingSP )
begin
SELECT * FROM ##DatabasesContainingSP
end
GO
IF OBJECT_ID('tempdb..##DatabasesContainingSP' , 'U') IS NOT NULL
drop TABLE ##DatabasesContainingSP;
Thank you for the quick responses.
I managed to solve it by creating a table and adding insert into this table in the beginning of my generated and concatenated code, which solved the problem since when reading the table in the end, it only shows the inserted results.
With kind regards,
Alexander
SQL stored procedures used some inner stored procedures.so I want to get all inner used stored procedures list in specific stored procedure in SQL server.i am using SQL server 2008.please help to find this solution.
use this to find the dependency
EXEC sp_depends #objName = N'Stored_Procedure_Name'
You can use the information_schema.routines combined with sys.sql_expression_dependencies - but you need it in a recursive fashion.
with recursedProcs(code_database, ancestorName, object, Recursion, procpath)
as
(
select isr.specific_catalog as code_database, isr.[specific_name] as ancestorName, cast(isr.specific_name as varchar(200)) as object, 1 as Recursion, cast(isr.specific_name as varchar(200)) as procpath
from information_schema.routines isr with (nolock)
union all
select p.code_database, p.ancestorName, cast(d.referenced_entity_name as varchar(200)), p.recursion + 1, cast(p.procpath + '/' + cast(d.referenced_entity_name as varchar(200)) as varchar(200))
from recursedProcs p
inner join sys.sql_expression_dependencies d on d.referencing_id = OBJECT_ID(p.object)
where p.recursion < 20
and d.referenced_id <> object_id(p.object)
)
select * from recursedProcs
This recurses down every procedure in the database, through sub-procedures and finally to the tables that a procedure depends on. From this starting point you can refine it to suit your needs. (If you have more than 20 levels deep of sub-procedures, you will also need to add a maxrecursion option and remove the <20 predicate)
sp_depends is deprecated going forward and does currently have the ability to give incorrect answers.
(1) Is there a good/reliable way to query the system catalogue in order
to find all stored procedures which create some temporary tables in their
source code bodies but which don't drop them at the end of their bodies?
(2) In general, can creating temp tables in a SP and not dropping
them in the same SP cause some problems and if so, what problems?
I am asking this question in the contexts of
SQL Server 2008 R2 and SQL Server 2012 mostly.
Many thanks in advance.
Not 100% sure if this is accurate as I don't have a good set of test data to work with. First you need a function to count occurrences of a string (shamelessly stolen from here):
CREATE FUNCTION dbo.CountOccurancesOfString
(
#searchString nvarchar(max),
#searchTerm nvarchar(max)
)
RETURNS INT
AS
BEGIN
return (LEN(#searchString)-LEN(REPLACE(#searchString,#searchTerm,'')))/LEN(#searchTerm)
END
Next make use of the function like this. It searches the procedure text for the strings and reports when the number of creates doesn't match the number of drops:
WITH CreatesAndDrops AS (
SELECT procedures.name,
dbo.CountOccurancesOfString(UPPER(syscomments.text), 'CREATE TABLE #') AS Creates,
dbo.CountOccurancesOfString(UPPER(syscomments.text), 'DROP TABLE #') AS Drops
FROM sys.procedures
JOIN sys.syscomments
ON procedures.object_id = syscomments.id
)
SELECT * FROM CreatesAndDrops
WHERE Creates <> Drops
1) probably no good / reliable way -- though you can extract the text of sp's using some arcane ways that you can find in other places.
2) In general - no this causes no problems -- temp tables (#tables) are scope limited and will be flagged for removal when their scope disappears.
and table variables likewise
an exception is for global temp tables (##tables) which are cleaned up when no scope holds a reference to them. Avoid those guys -- there are usually (read almost always) better ways to do something than with a global temp table.
Sigh -- if you want to go down the (1) path then be aware that there are lots of pitfalls in looking at code inside sql server -- many of the helper functions and information tables will truncate the actual code down to a NVARCHAR(4000)
If you look at the code of sp_helptext you'll see a really horrible cursor that pulls the actual text..
I wrote this a long time ago to look for strings in code - you could run it on your database -- look for 'CREATE TABLE #' and 'DROP TABLE #' and compare the outputs....
DECLARE #SearchString VARCHAR(255) = 'DELETE FROM'
SELECT
[ObjectName]
, [ObjectText]
FROM
(
SELECT
so.[name] AS [ObjectName]
, REPLACE(comments.[c], '#x0D;', '') AS [ObjectText]
FROM
sys.objects AS so
CROSS APPLY (
SELECT CAST([text] AS NVARCHAR(MAX))
FROM syscomments AS sc
WHERE sc.[id] = so.[object_id]
FOR XML PATH('')
)
AS comments ([c])
WHERE
so.[is_ms_shipped] = 0
AND so.[type] = 'P'
)
AS spText
WHERE
spText.[ObjectText] LIKE '%' + #SearchString + '%'
Or much better - use whatever tool of choice you like on your codebase - you've got all your sp's etc scripted out into source control somewhere, right.....?
I think SQL Search tool from red-gate would come handy in this case. You can download from here. This tool will find the sql text within stored procedures, functions, views etc...
Just install this plugin and you can find sql text easily from SSMS.
I have created a SQL CLR trigger with the follow SQL:
GO
CREATE TRIGGER AuditAccountsTable
ON [dbo].[Accounts]
FOR INSERT,DELETE,UPDATE
AS
EXTERNAL NAME namespace.Triggers.AuditTrigger
I am trying to query:
select * from sys.triggers
Is there a way to find the: EXTERNAL NAME namespace.Triggers.AuditTrigger on the trigger from querying in the DB?
I can't be sure as I don't have a place to test this, but does the text column returned below get you close to what you're looking for?
select t.name, c.text
from sys.triggers t
inner join sys.syscomments c
on t.object_id = c.id
where t.type_desc = 'CLR_TRIGGER'
Unlike T-SQL "modules" such as Stored Procedures and Functions, the SQLCLR T-SQL wrapper objects do not have their CREATE statements stored in the database. This is why you cannot access them via sys.sql_modules, OBJECT_DEFINITION, or the deprecated-since-SQL-Server-2005-and-should-not-be-used sys.syscomments. This is why SQLCLR Stored Procedures and Functions need to have their parameter default values stored in sys.parameters
Instead, CREATE statements for SQLCLR T-SQL wrapper objects are inferred from meta-data, just like Indexes, Primary Keys, Foreign Keys, etc.
You can get all of the parts of the CREATE TRIGGER statement from the following query:
SELECT OBJECT_SCHEMA_NAME(st.[object_id]) AS [SchemaName],
st.[name] AS [TriggerName],
OBJECT_SCHEMA_NAME(st.parent_id) AS [ParentSchemaName],
OBJECT_NAME(st.parent_id) AS [ParentName],
st.is_instead_of_trigger,
SUBSTRING((
SELECT N', ' + ste.[type_desc]
FROM sys.trigger_events ste
WHERE ste.[object_id] = st.[object_id]
FOR XML PATH ('')
), 3, 500) AS [Actions],
QUOTENAME(sa.name) AS [AssemblyName],
QUOTENAME(sam.assembly_class) AS [AssemblyClass],
QUOTENAME(sam.assembly_method) AS [AssemblyMethod]
FROM sys.triggers st
INNER JOIN sys.assembly_modules sam
ON sam.[object_id] = st.[object_id]
INNER JOIN sys.assemblies sa
ON sa.[assembly_id] = sam.[assembly_id]
WHERE st.parent_class = 1; --- OBJECT_OR_COLUMN
I have a stored procedure (see below) which inserts data into a physical table and then joins information with sys.databases. I was thinking that would it be better to not have a physical table for data insertion? Would it be better to fetch these results into a table variable within this procedure? If so, how to do that?
CREATE PROCEDURE dbo.PROC_getDbInfo
AS
SET NOCOUNT ON
GO
TRUNCATE TABLE dbo.dbinfo
GO
EXECUTE sp_msforeachdb 'insert into dbo.dbinfo
select ''?'' as name,
type_desc,
physical_name,
state_desc,
size * 1.0/128 as size_in_mb,
max_size,
growth * 1.0/128 as growth_in_mb,
is_percent_growth,
is_read_only
from [?].sys.database_files'
GO
SELECT ##SERVERNAME as instance_name,
f.name,
d.create_date,
d.compatibility_level,
d.collation_name,
d.user_access_desc,
d.state_desc,
d.recovery_model_desc,
d.page_verify_option_desc,
d.log_reuse_wait_desc,
f.type_desc,
f.physical_name,
f.state_desc,
f.size_in_mb,
f.max_size,
f.growth_in_mb,
f.is_percent_growth,
f.is_read_only
FROM dbo.dbinfo AS f INNER JOIN
sys.databases AS d
ON f.name = d.name
ORDER BY f.name
GO
You'll have to use a table. Either global temp (##) or a normal table.
A table variable will not be in scope for the sp_msforeachdb call if declared for the stored proc, and not visible to the stored proc if declared in sp_msforeachdb
#table is better -- the table is small and the i/o cost will slow it down.
Table variable usage is explained here:
http://msdn.microsoft.com/en-us/library/ms175010.aspx
It basically behaves like a table when it comes to how your script looks - but has very different behaviour under the hood, and if it's small enough should not result in any disc IO.
Also, if the table is only used and then removed during the course of a procedure, this scope limitation becomes a argument for using it.