Query to Recursively Identify Object Dependencies - sql-server

I have a complex query with several tables, views and functions within it. The functions and views split off into more views and functions that potentially split off into more views and functions within them.
This query is having performance issues so I want to get a clear and concise list of all the objects that are being referenced within my query so I have a basis for my investigation. How do I get this list of objects?

DESCRIPTION
Wrote this Stored Procedure below which RECURSIVELY lists all the dependent child objects and child's dependent objects and child's child...etc. The input parameter can be Stored Proc, User Function, View.
Can easily be altered to get a Unique List of Column 5, regardless of what Level the Object was called and how deep and by which object.
COLUMNS
UsedByObjectId - The parent object that uses the dependent object
UsedByObjectName - The name of the parent object
UsedByObjectType - Type of the parent object (P,V,FN)
DependentObjectId - The child object the parent uses
DependentObjectName - Name of the child object
DependentObjectType - Type of the dependent child object (P,V,FN, U)
Level - How deep, the nested recursive level which the object is used
THE CODE
--=========================================================================
--=========================================================================
--== utlGetAllDependentObjectsRecursive - Uses recursive common table
--== expression to recursively get all the dependent objects as well
--== as the child objects and child's child objects of a
--== Stored Procedure or View or Function. can be easily modified to
--== include all other types of Objects
--=========================================================================
--=========================================================================
CREATE PROCEDURE utlGetAllDependentObjectsRecursive
(
-- Supports Stored Proc, View, User Function, User Table
#PARAM_OBJECT_NAME VARCHAR(500)
)
AS
BEGIN
WITH CTE_DependentObjects AS
(
SELECT DISTINCT
b.object_id AS UsedByObjectId,
b.name AS UsedByObjectName, b.type AS UsedByObjectType,
c.object_id AS DependentObjectId,
c.name AS DependentObjectName , c.type AS DependenObjectType
FROM sys.sysdepends a
INNER JOIN sys.objects b ON a.id = b.object_id
INNER JOIN sys.objects c ON a.depid = c.object_id
WHERE b.type IN ('P','V', 'FN') AND c.type IN ('U', 'P', 'V', 'FN')
),
CTE_DependentObjects2 AS
(
SELECT
UsedByObjectId, UsedByObjectName, UsedByObjectType,
DependentObjectId, DependentObjectName, DependenObjectType,
1 AS Level
FROM CTE_DependentObjects a
WHERE a.UsedByObjectName = #PARAM_OBJECT_NAME
UNION ALL
SELECT
a.UsedByObjectId, a.UsedByObjectName, a.UsedByObjectType,
a.DependentObjectId, a.DependentObjectName, a.DependenObjectType,
(b.Level + 1) AS Level
FROM CTE_DependentObjects a
INNER JOIN CTE_DependentObjects2 b
ON a.UsedByObjectName = b.DependentObjectName
)
SELECT DISTINCT * FROM CTE_DependentObjects2
ORDER BY Level, DependentObjectName
END

I saw this post to identify all the objects that reference a particular synonym and used the base logic in the answer in a recursive CTE to identify all the objects related to a comma-delimited list of the objects within the top level query being executed.
Declare #baseObjects Nvarchar(1000) = '[Schema].[Table],[Schema].[View],[Schema].[Function],[Schema].[StoredProc]',
#SQL Nvarchar(Max);
Declare #objects Table (SchemaName Varchar(512), TableName Varchar(512), ID Int, xtype Varchar(10));
Set #SQL = 'Select ss.name As SchemaName,
so.name As TableName,
so.id,
so.xtype
From sysobjects so
Join sys.schemas ss
On so.uid = ss.schema_id
Where so.id In (Object_ID(''' + Replace(#baseObjects,',','''),Object_ID(''') + '''))';
Insert #objects
Exec sp_executeSQL #SQL;
With test As
(
Select ss.name As SchemaName,
so.name As TableName,
so.id,
so.xtype
From sys.sql_expression_dependencies sed
Join #objects vo
On sed.referencing_id = vo.ID
Join sysobjects so
On sed.referenced_id = so.id
Join sys.schemas ss
On so.uid = ss.schema_id
Union All
Select ss.name As SchemaName,
so.name As TableName,
so.id,
so.xtype
From test
Join sys.sql_expression_dependencies sed
On sed.referencing_id = test.id
And sed.referencing_id <> sed.referenced_id
Join sysobjects so
On sed. referenced_id = so.id
Join sys.schemas ss
On so.uid = ss.schema_id
)
Select Distinct *
From test
Union
Select *
From #objects;

Check This one, You will get all recursive objects.
WITH Refobjects
(referencing_object_name,referencing_object_type_desc)
AS
(
SELECT
o.name AS referencing_object_name,
o.type_desc AS referencing_object_type_desc
FROM
sys.sql_expression_dependencies sed
INNER JOIN
sys.objects o ON sed.referencing_id = o.[object_id]
WHERE
sed.referenced_entity_name = 'Your Object Name'
UNION ALL
SELECT
o.name AS referencing_object_name,
o.type_desc AS referencing_object_type_desc
FROM
sys.sql_expression_dependencies sed
INNER JOIN
sys.objects o ON sed.referencing_id = o.[object_id]
INNER JOIN Refobjects ON sed.referenced_entity_name = Refobjects.referencing_object_name
)
SELECT distinct * FROM Refobjects
Order by 2 desc,1 ;

In SQL Server 2008 there are two new Dynamic Management Functions introduced to keep track of object dependencies: sys.dm_sql_referenced_entities and sys.dm_sql_referencing_entities:
1/ Returning the entities that refer to a given entity:
SELECT
referencing_schema_name, referencing_entity_name,
referencing_class_desc, is_caller_dependent
FROM sys.dm_sql_referencing_entities ('<TableName>', 'OBJECT')
2/ Returning entities that are referenced by an object:
SELECT
referenced_schema_name, referenced_entity_name, referenced_minor_name,
referenced_class_desc, is_caller_dependent, is_ambiguous
FROM sys.dm_sql_referenced_entities ('<StoredProcedureName>', 'OBJECT');
Another option is to use a pretty useful tool called SQL Dependency Tracker from Red Gate.

Based on #Raju Chavan's answer above, which works great. However...
I've added support for schemas, as well as returning (and ordering by) the recursion level, so one can easily turn it into a script to refresh referencing objects in the correct order, using sp_refreshsqlmodule (see point 3 below).
WITH
cRefobjects AS (
SELECT o.name, s.name AS sch, o.type_desc, 1 AS level
FROM sys.sql_expression_dependencies sed
INNER JOIN sys.objects o ON o.object_id = sed.referencing_id
INNER JOIN sys.schemas AS s ON s.schema_id = o.schema_id
WHERE (sed.referenced_schema_name = '<your schema>' OR sed.referenced_schema_name IS NULL)
AND sed.referenced_entity_name = '<your object name>'
UNION ALL
SELECT o.name, s.name AS sch, o.type_desc, cRefobjects.level + 1 AS level
FROM
sys.sql_expression_dependencies AS sed
INNER JOIN sys.objects o ON o.object_id = sed.referencing_id
INNER JOIN sys.schemas AS s ON s.schema_id = o.schema_id
INNER JOIN cRefobjects ON sed.referenced_entity_name = cRefobjects.name
AND sed.referenced_schema_name = cRefobjects.sch
)
SELECT DISTINCT name, sch, type_desc, level
FROM cRefobjects
ORDER BY level, type_desc DESC, name;
A few things to consider:
Replace <your schema> and <your object> with with what you require.
When the referenced object does not have a schema prefix in the referencing object, the schema is actually unknown, hence the predicate above OR sed.referenced_schema_name IS NULL. This may get the wrong referencing object if you're not following best practices in your database objects.
My goal in seeking and finding this answer was to write a script to refresh referenced objects in the database automatically after editing a view, using sp_refreshsqlmodule. To do this, just wrap the CTE shown above as follows. This prints the required SQL for refreshing the referencing objects in the correct order:
DECLARE #SQL NVARCHAR(4000); SET #SQL = '';
WITH
cRefobjects AS (
...
)
--SELECT DISTINCT name, sch, type_desc, level
SELECT #SQL = #SQL + 'EXEC sys.sp_refreshsqlmodule ''' + sch + '.' + name + '''' + CHAR(13)+CHAR(10)
FROM cRefobjects
ORDER BY level, type_desc DESC, name;
PRINT #SQL

I have improved above answers as none was working for me.
I needed a way to refresh complex nested objects by type sp_refreshsqlmodule.
You need to update and <TYPE_NAME> to your own.
Following method work for me:
WITH cRefobjects AS (
SELECT o.name, s.name AS sch, o.type, 1 AS level
FROM sys.sql_expression_dependencies sed
INNER JOIN sys.objects o ON o.object_id = sed.referencing_id
INNER JOIN sys.schemas AS s ON s.schema_id = o.schema_id
WHERE (sed.referenced_schema_name = '<SCHEMA>' OR sed.referenced_schema_name IS NULL)
AND sed.referenced_entity_name = '<TYPE_NAME>'
UNION ALL
SELECT o.name, s.name AS sch, o.type, cRefobjects.level + 1 AS level
FROM
sys.sql_expression_dependencies AS sed
INNER JOIN sys.objects o ON o.object_id = sed.referencing_id
INNER JOIN sys.schemas AS s ON s.schema_id = o.schema_id
INNER JOIN cRefobjects ON sed.referenced_entity_name = cRefobjects.name
AND sed.referenced_schema_name = cRefobjects.sch
)
SELECT name, MAX(level) as level, 'EXEC sys.sp_refreshsqlmodule #name = ''' + sch + '.' + name + '''', type
FROM cRefobjects
GROUP BY name, sch, type
ORDER BY level, type, name;

Related

Check If column exists or not in table and rename them

I am trying to merge two different rules into one that should run in two databases server.
I did merged the files. but i am stuck at the this columns.
There are two columns with different names but the same data in the two databases. I want my query to check if if this column exist
First column - APE.RecProdOwner
Second Column - APE.ReconciliationOwner
I want my query to check for both these columns in the database and if one of the two exists then it should store the data into the new column name as “RecProdOwner”
You can use an EXISTS against the sys objects, and then simply use sys.sp_rename to rename the column:
USE Sandbox;
GO
CREATE TABLE dbo.YourTable ([APE.RecProdOwner] int,
ReconciliationOwner int);
GO
IF EXISTS (SELECT 1
FROM sys.schemas s
JOIN sys.tables t ON s.schema_id = t.schema_id
JOIN sys.columns c ON t.object_id = c.object_id
WHERE s.name = N'dbo'
AND t.name = N'YourTable'
AND c.name = N'APE.RecProdOwner')
EXEC sys.sp_rename N'dbo.YourTable.[APE.RecProdOwner]','RecProdOwner','COLUMN';
IF EXISTS (SELECT 1
FROM sys.schemas s
JOIN sys.tables t ON s.schema_id = t.schema_id
JOIN sys.columns c ON t.object_id = c.object_id
WHERE s.name = N'dbo'
AND t.name = N'YourTable'
AND c.name = N'APE.ReconciliationOwner')
EXEC sys.sp_rename N'dbo.YourTable.[APE.ReconciliationOwner]','ReconciliationOwner','COLUMN';
GO
SELECT *
FROM dbo.YourTable;
GO
DROP TABLE dbo.YourTable;

Find all dependencies of a list of stored procedures

We have a list of 51 stored procedures used in our application.
I need to find out the names of all the functions and stored procedures called by those stored procs
Is there a quick way to find out what our stored procedures are calling?
I tried using sys.dm_sql_referencing_entities as below
SELECT
referencing_schema_name +'.'+ referencing_entity_name AS ReferencedEntityName,
referencing_class_desc AS ReferencingEntityDescription
FROM sys.dm_sql_referencing_entities ('dbo.sp_GetPayRunDetails', 'OBJECT');
GO
but I am hoping that there is a way to check all 50 stored procs and get detailed information about what other objects (stored procs, and functions) that they call...
I don't want to do this manually is because I also need recursive dependencies for the stored procs and functions that are called...
This query might do the trick for you:
WITH cteDependencies AS (
SELECT e.referencing_id object_id, e.referencing_id, e.referenced_id, e.referenced_schema_name, e.referenced_entity_name
FROM sys.sql_expression_dependencies e
WHERE e.referencing_id = OBJECT_ID('dbo.sp_GetPayRunDetails')
UNION ALL
SELECT d.object_id, e.referencing_id, e.referenced_id, e.referenced_schema_name, e.referenced_entity_name
FROM sys.sql_expression_dependencies e
JOIN cteDependencies d ON d.referenced_id = e.referencing_id AND e.referenced_id <> e.referencing_id
)
SELECT OBJECT_NAME(d.object_id) source_name, d.*
FROM cteDependencies d
JOIN sys.all_objects o ON d.referenced_id = o.object_id
WHERE o.[type] IN ('P','FN','TF'); -- for a list of types see https://msdn.microsoft.com/en-us/library/ms178618.aspx?f=255&MSPPError=-2147217396
Note that it will fail on circular references; if you have such, you need to track the dependency path (for instance in a XML column) and skip items which are repeated.
You can change the "source" by altering the OBJECT_ID('dbo.sp_GetPayRunDetails') filter to include the SPs you want to analyze.
I had a function. Modify it as per your means. It manages self-references
CREATE FUNCTION GetDependents(
#ObjectName AS SYSNAME
)
RETURNS #result TABLE ( Seq INT IDENTITY, ObjectName SYSNAME, Hierarchy VARCHAR(128) , objNameStr varchar(max) )
AS
BEGIN
;WITH Obj AS (
SELECT DISTINCT s.id AS ParentID, s.DepID AS ObjectID, o1.Name AS ParentName, o2.Name AS ChildName,
QUOTENAME(sch1.name) + '.' + QUOTENAME(o1.Name) + '(' + RTRIM(o1.type) + ')' COLLATE SQL_Latin1_General_CP1_CI_AS
AS ParentObject,
QUOTENAME(sch2.name) + '.' + QUOTENAME(o2.Name) + '(' + RTRIM(o2.type) + ')' COLLATE SQL_Latin1_General_CP1_CI_AS AS ObjectName,
o2.Name as objNameStr
FROM sys.sysdepends s
INNER JOIN sys.all_objects o1 ON s.id = o1.object_id
INNER JOIN sys.schemas sch1 ON sch1.schema_id = o1.schema_id
INNER JOIN sys.all_objects o2 on s.DepID = o2.object_id
INNER JOIN sys.schemas sch2 ON sch2.schema_id = o2.schema_id
where o2.type not in ('u') and s.id <>s.DepID --Self Reference ko hata...
), cte AS (
SELECT
0 AS lvl,
ParentID,
ObjectId,
ParentObject,
ObjectName,
CAST(ObjectID AS VARBINARY(512)) AS Sort
, objNameStr
FROM obj WHERE ParentName = #ObjectName
UNION ALL
SELECT
p.lvl+ 1,
c.ParentID,
c.ObjectId,
c.ParentObject,
c.ObjectName,
CAST(p.sort + CAST(c.ObjectID AS VARBINARY(16))
AS VARBINARY(512)), c.objNameStr
FROM cte p
INNER JOIN obj c ON p.ObjectID = c.ParentID
)
INSERT INTO #result (ObjectName, Hierarchy,objNameStr)
SELECT
ObjectName,
'|-' + REPLICATE('-',(lvl * 4)) + ObjectName,
objNameStr
FROM cte
ORDER BY Sort
OPTION (MAXRECURSION 32767);
RETURN
END

Get total size for a list of tables

I have a prod database that is very large in size. I need to copy this DB to make a test environment, however there is not enough disk space.
But actually there is no need to copy rows from tables containing user-data, only those tables that describe functionality are necessary. For tables with user-data I only need to copy table "description" (columns, indexes, triggers, ...).
How (with what query) can I estimate the size of DB without data from some tables?
SET NOCOUNT ON
DBCC UPDATEUSAGE(0)
-- DB size.
EXEC sp_spaceused
-- Table row counts and sizes.
CREATE TABLE #t
(
[name] NVARCHAR(128),
[rows] CHAR(11),
reserved VARCHAR(18),
data VARCHAR(18),
index_size VARCHAR(18),
unused VARCHAR(18)
)
INSERT #t EXEC sp_msForEachTable 'EXEC sp_spaceused ''?'''
SELECT *
FROM #t
-- # of rows.
SELECT SUM(CAST([rows] AS int)) AS [rows]
FROM #t
DROP TABLE #t
*by Alexander Groß *
Link to source
SELECT
schema_qualified_table = s.name + '.' + t.name,
KB = SUM(ps.reserved_page_count) * 8192/1024.0
FROM sys.tables AS t
INNER JOIN sys.schemas AS s ON t.[schema_id] = s.[schema_id]
INNER JOIN sys.dm_db_partition_stats AS ps
ON t.[object_id] = ps.[object_id]
WHERE s.name + '.' + t.name IN (N'dbo.table1', N'dbo.table2', ...)
-- list of tables you do care about ^^^^^^^^^^ ^^^^^^^^^^
GROUP BY s.name + '.' + t.name;
A little tidier might be:
;WITH x AS
(
SELECT o = t.[object_id], n = s.name + '.' + t.name
FROM sys.tables AS t
INNER JOIN sys.schemas AS s
ON t.[schema_id] = s.[schema_id]
)
SELECT
schema_qualified_table = x.n,
KB = SUM(ps.reserved_page_count) * 8192/1024.0
FROM x INNER JOIN sys.dm_db_partition_stats AS ps
ON x.o = ps.[object_id]
WHERE x.n IN (N'dbo.table1', N'dbo.table2', ...);
Posting my expansion to Aaron Bertrand's answer, just for readability. Only difference is adding the join to the SCHEMAS table, and including schema name in the output and group by.
SELECT
s.name,
t.name,
KB = SUM(ps.reserved_page_count) * 8192/1024.0
FROM sys.tables AS t
INNER JOIN sys.dm_db_partition_stats AS ps
ON t.[object_id] = ps.[object_id]
INNER JOIN sys.schemas S
ON t.schema_id = s.schema_id
WHERE t.name IN (<YOUR TABLES GO HERE) -- list of tables you do care about
GROUP BY t.name,
s.name;
As Aaron has rightly pointed out, trying to filter on a combination of tables and schemas could get ugly very fast. You could easily end up with a huge collection of ORs:
(S.SCHEMA = 'SCHEMA1' and T.NAME = 'FOO')
OR
(S.SCHEMA = 'SCHEMA2' and T.NAME = 'FOO')
OR
(S.SCHEMA = 'SCHEMA1' and T.name = 'BAR')
...

Query that returns list of all stored procedures in a SQL Server database which have varchar as a parameter

Is there a query that returns the names of all the stored procedures in a SQL Server database that some or all his parameter has varchar datatype, and we can change it because we change all database table from varchar to nvarchar and there are a lot of stored procedures to change then maybe it takes a whole day so please help me
Information_Schema has always helped me with these problems:
SELECT r.ROUTINE_NAME, p.PARAMETER_NAME
FROM
INFORMATION_SCHEMA.ROUTINES r INNER JOIN INFORMATION_SCHEMA.PARAMETERS p
ON r.SPECIFIC_CATALOG = p.SPECIFIC_CATALOG
AND r.SPECIFIC_SCHEMA = p.SPECIFIC_SCHEMA
AND r.SPECIFIC_NAME = p.SPECIFIC_NAME
WHERE
p.DATA_TYPE = 'varchar'
Sure - try this:
SELECT
ProcedureName = pr.Name,
ParameterName = p.Name,
TypeName = t.Name
FROM
sys.procedures pr
INNER JOIN
sys.parameters p ON p.object_id = pr.object_id
INNER JOIN
sys.types t ON p.system_type_id = t.system_type_id
WHERE
t.Name = 'varchar'
You might also want to search for parameters of type char (which need to be converted to nchar) and text (convert to ntext - or better yet: nvarchar(max) since text and ntext are deprecated and should not be used anymore)
Try this one -
SELECT
[procedure_name] = SCHEMA_NAME(o.[schema_id]) + '.' + o.name
, parameter_name = p.name
FROM sys.objects o WITH(NOWAIT)
JOIN sys.parameters p WITH(NOWAIT) ON p.[object_id] = o.[object_id]
WHERE TYPE_NAME(p.user_type_id) = 'varchar'
AND o.[type] IN ('P ', 'X ', 'PC', 'RF')

Query the contents of stored procedures on SQL Server

I am exploring a legacy database system and have very little knowledge of its internals. I would like to find all the stored procedures that invoke another stored procedure A.
How best to do this?
Can I write something like this pseudocode:
select name from AllStoredProcedures as Asp where Asp.TextualContent contains 'A'
Asp.TextualContent means the actual SQL contained in the SP.
SELECT OBJECT_NAME(object_id),
definition
FROM sys.sql_modules
WHERE objectproperty(object_id,'IsProcedure') = 1
AND definition like '%Foo%'
For SQL Server 2005/2008:
SELECT s.name SchemaName
,o.name RoutineName
,o.[type] RoutineType
,procs.*
FROM sys.sql_modules procs
INNER JOIN sys.objects o ON procs.object_id = o.object_id
INNER JOIN sys.schemas s ON o.schema_id = s.schema_id
WHERE procs.[definition] LIKE '%A%'
--AND o.[type] = 'P' --'P' for stored procedures
This query will retrieve the textual definition of stored procedures and filter using a simple wildcard.
For 2000 (untested, but IIRC it's the right table):
select p.[type]
,p.[name]
,c.[text]
from sysobjects p
join syscomments c
on p.object_id = c.id
where p.[type] = 'P'
and c.[text] like '%foo%'
For 2005:
select p.[type]
,p.[name]
,c.[text]
from sys.objects p
join sys.syscomments c
on p.object_id = c.id
where p.[type] = 'P'
and c.[text] like '%foo%'
For 2005 and 2008+
select p.[type]
,p.[name]
,c.[definition]
from sys.objects p
join sys.sql_modules c
on p.object_id = c.object_id
where p.[type] = 'P'
and c.[definition] like '%foo%'
Try This only one statement can solve your problem..
--note this does not show /r/n, it comes out as one long line
SELECT OBJECT_DEFINITION(OBJECT_ID(N'dbo.myStoredProc'))
or
DECLARE #objname nvarchar(max); -- note this truncates
SELECT #objname= OBJECT_DEFINITION(OBJECT_ID(N'dbo.myStoredProc'))
print #objname

Resources