How to Find the list of Stored Procedures which affect a particular column? - sql

Im working on this large DB which has a lot of the business knowledge embedded in the SPs[I know!] and there is a lot of chaining between the SPs. i.e one stored proc calling another.
Im want to find out a list of stored procedures which update a particular column. How would I do that.
Using showplan_All as outlined in
SQL Table and column Parser for stored procedures doesnt work for me, because this is a shared dev db.
using a Sp from master db scanning system text as described is not feasible because I dont have access to the master db.
So how can I find this informaion?

From system view sys.sql_dependencies you can get dependencies at column level.
DECLARE #Schema SYSNAME
DECLARE #Table SYSNAME
DECLARE #Column SYSNAME
SET #Schema = 'dbo'
SET #Table = 'TableName'
SET #Column = 'ColumnName'
SELECT o.name
FROM sys.sql_dependencies AS d
INNER JOIN sys.all_objects AS o ON o.object_id = d.object_id
INNER JOIN sys.all_objects AS ro ON ro.object_id = d.referenced_major_id
INNER JOIN sys.all_columns AS c ON c.object_id = ro.object_id AND c.column_id = d.referenced_minor_id
WHERE (SCHEMA_NAME(ro.schema_id)=#Schema)
and o.type_desc = 'SQL_STORED_PROCEDURE'
and ro.name = #Table
and c.name = #Column
GROUP BY o.name

Have you tried this : EXEC sp_depends #objname = [table name of the column you are interested in].
So for example, if you had a column named Price in a table named Product, you would execute this: EXEC sp_depends #objname = N'Product'.
Simply executing this would give you list of all sps, views, etc which depend on that particular table.
I use this all the time as I work with a db which has over 400 tables :-)
sp_depends page on MSDN

Try something like this:
use YourDatabase;
select [Name]
from sys.procedures
where object_definition([object_id]) like '%YourColumnName%';
Obviously this has the potential to generate a lot of false positives depending on what the column is named but at least you will have a list of procedures to sift through.

Here's one that works in SQL 2000+; Note that as Andrew noted in his, you will get false positives depending on your column name, but it's a starting place:
SELECT DISTINCT o.Name
FROM syscomments c
JOIN sysobjects o ON c.ID = o.ID
WHERE c.Text LIKE '%ColumnName%'
ORDER BY o.Name

use msdb
go
select * from sysjobs j
inner join sysjobsteps s
on j.job_id=s.job_id
where command like '%HBR_INSTRUMENT%'

Related

extract a string from a stored proc definition

I need to check the library used by several stored procs that extract data from a remote server.
I have (with SO help, see SO 21708681) built the below code:
DECLARE #tProcs TABLE
(
procID int IDENTITY,
procObjectID nvarchar(100),
procName nvarchar(100)
);
insert into #tProcs
SELECT object_id, name
FROM sys.objects
WHERE type in (N'P', N'PC') and name like '%_Extract'
declare #countProcs int, #I int=0
select #countProcs=COUNT(*) from #tProcs
while #I<#countProcs
Begin
declare #source_code nvarchar(max)
declare #objectID nvarchar(50)
declare #proc_Name nvarchar(200)
select #objectID=procObjectID from #tProcs where procID=#I
select #proc_Name=procName from #tProcs where procID=#I
select #source_code = definition
from sys.sql_modules
where object_id = #objectID
SELECT PATINDEX('BOCTEST.%', #proc_Name) as Pos, #proc_Name
-- or SELECT charindex(#source_code, '%BOCTEST%')
set #I=#I+1
End
Inside each of the target stored procs there is a line like this:
DECLARE YP040P_cursor CURSOR FOR SELECT * FROM BOCTEST.S653C36C.LIVEBOC_A.YP040P
I need to know for each of the stored procs the part 'LIVEBOC_A' (which can either be 'LIVEBOC_A' or LIVEBOC_B)
I tried to use PATINDEX and CHARINDEX to get the location of the start opf that string in the definition from sysmodules but all I get back is either zero or an error that string or binary data would be truncated.
try
SELECT
name,
table_name = CASE WHEN OBJECT_DEFINITION(OBJECT_ID) LIKE '%BOCTEST.S653C36C.LIVEBOC_A.YP040P%' THEN 'LIVEBOC_A'
WHEN OBJECT_DEFINITION(OBJECT_ID) LIKE '%BOCTEST.S653C36C.LIVEBOC_B.YP040P%' THEN 'LIVEBOC_B' END
FROM sys.objects o
WHERE o.[type] IN ('P', 'PC')
AND name like '%_Extract'
You can do what you want with a query like this one:
select name = s.name + '.' + p.name ,
dt_created = p.create_date ,
dt_modified = p.modify_date ,
livboc_usage = case
when m.definition like '%declare%cursor%boctext.[^.].LIVEBOC_A.%' then 'A'
when m.definition like '%declare%cursor%boctext.[^.].LIVEBOC_B.%' then 'B'
else null
end
from sys.schemas s
join sys.procedures p on p.schema_id = s.schema_id
join sys.sql_modules m on m.object_id = p.object_id
But since what you're looking for are cross-server dependencies of a table, you should be able to get that simply by querying the system view sys.sql_expression_dependencies, which
Contains one row for each by-name dependency on a user-defined entity in the current
database. A dependency between two entities is created when one entity, called the
referenced entity, appears by name in a persisted SQL expression of another entity,
called the referencing entity. For example, when a table is referenced in the definition
of a view, the view, as the referencing entity, depends on the table, the referenced
entity. If the table is dropped, the view is unusable.
You can use this catalog view to report dependency information for the following
entities:
Schema-bound entities.
Non-schema-bound entities.
Cross-database and cross-server entities.
Entity names are reported; however, entity IDs are not resolved.
Column-level dependencies on schema-bound entities.
Column-level dependencies for non-schema-bound objects can be returned
by using sys.dm_sql_referenced_entities.
Server-level DDL triggers when in the context of the master database.
To that end, running a query like this in the database the referencing stored procedures live should do you:
select name = o.name ,
type = o.type_desc ,
liveboc_usage = case d.referenced_schema_name
when 'liveboc_a' then 'A'
when 'liveboc_b' then 'B'
else null
end ,
has_dependency_on = d.referenced_server_name
+ '.' + d.referenced_database_name
+ '.' + d.referenced_schema_name
+ '.' + d.referenced_entity_name
from sys.sql_expression_dependencies d
join sys.objects o on o.object_id = d.referenced_id
join sys.schemas s on s.schema_id = o.schema_id
where d.referenced_server_name = 'BOCTEST'
and d.referenced_database_name = 'S653C36C'
and d.referenced_schema_name like 'LIVEBOC_[AB]'
and d.referenced_entity_name = 'YP040P'

Is there a way to find all invalid columns that are referenced in a view using SQL Server 2012?

I have inherited a large database project with thousands of views.
Many of the views are invalid. They reference columns that no longer exist. Some of the views are very complex and reference many columns.
Is there an easy way to track down all the incorrect columns references?
This answer finds the underlying columns that were originally defined in the views by looking at sys.views, sys.columns and sys.depends (to get the underlying column if the column has been aliased). It then compares this with the data held in INFORMATION_Schema.VIEW_COLUMN_USAGE which appears to have the current column usage.
SELECT SCHEMA_NAME(v.schema_id) AS SchemaName,
OBJECT_NAME(v.object_id) AS ViewName,
COALESCE(alias.name, C.name) As MissingUnderlyingColumnName
FROM sys.views v
INNER JOIN sys.columns C
ON C.object_id = v.object_id
LEFT JOIN sys.sql_dependencies d
ON d.object_id = v.object_id
LEFT JOIN sys.columns alias
ON d.referenced_major_id = alias.object_id AND c.column_id= alias.column_id
WHERE NOT EXISTS
(
SELECT * FROM Information_Schema.VIEW_COLUMN_USAGE VC
WHERE VIEW_NAME = OBJECT_NAME(v.object_id)
AND VC.COLUMN_NAME = COALESCE(alias.name, C.name)
AND VC.TABLE_SCHEMA = SCHEMA_NAME(v.schema_id)
)
For the following view:
create table test
( column1 varchar(20), column2 varchar(30))
create view vwtest as select column1, column2 as column3 from test
alter table test drop column column1
The query returns:
SchemaName ViewName MissingUnderlyingColumnName
dbo vwtest column1
This was developed with the help of this Answer
UPDATED TO RETRIEVE ERROR DETAILS
So this answer gets you what you want but it isn't the greatest code.
A cursor is used (yes I know :)) to execute a SELECT from each view in a TRY block to find ones that fail. Note I wrap each statement with a SELECT * INTO #temp FROM view X WHERE 1 = 0 this is to stop the EXEC returning any results and the 1=0 is so that SQL Server can optimize the query so that it is in effect a NO-OP.
I then return a list of any views whose sql has failed.
I haven't performed lots of testing on this, but it appears to work. I would like to get rid of the execution of each SELECT from View.
So here it is:
DECLARE curView CURSOR FOR
SELECT v.name AS ViewName
FROM sys.views v
INNER JOIN sys.sql_modules m
on v.object_id = m.object_id
OPEN curView
DECLARE #viewName SYSNAME
DECLARE #failedViews TABLE
(
FailedViewName SYSNAME,
ErrorMessage VARCHAR(MAX)
)
FETCH NEXT FROM curView
INTO #ViewName
WHILE ##FETCH_STATUS = 0
BEGIN
BEGIN TRY
exec ('SELECT * INTO #temp FROM ' + #viewName + ' WHERE 1=0' )
END TRY
BEGIN CATCH
INSERT INTO #failedViews VALUES (#viewName, ERROR_MESSAGE())
END CATCH
FETCH NEXT FROM curView
INTO #ViewName
END
CLOSE curView
DEALLOCATE curView
SELECT *
FROM #failedViews
An example of an ERROR returned is:
FailedViewName ErrorMessage
--------------- -------------
vwtest Invalid column name 'column1'.
You could use system tables get information.
SELECT v.VIEW_NAME,v.TABLE_CATALOG,v.TABLE_SCHEMA,v.TABLE_NAME,v.COLUMN_NAME
from INFORMATION_SCHEMA.VIEW_COLUMN_USAGE v
left outer join INFORMATION_SCHEMA.COLUMNS c
ON v.TABLE_CATALOG=c.TABLE_CATALOG AND v.TABLE_SCHEMA=c.TABLE_SCHEMA AND v.TABLE_NAME=c.TABLE_NAME AND v.COLUMN_NAME=c.COLUMN_NAME
WHERE c.TABLE_NAME IS NULL
ORDER BY v.VIEW_NAME

Invalid Column with "FOR XML AUTO"

I've got a typical "invalid column name" in one of my stored procedures, but I'm struggling to understand how any of the popular workarounds can solve my problem :(
My stored procedure does something like:
IF EXISTS (SELECT * FROM sysobjects o
JOIN syscolumns c
ON o.id = c.id
WHERE o.Name = 'Table_A'
AND c.Name = 'Column_A')
BEGIN
SELECT * FROM Table_B
JOIN Table_A
ON Table_B.Column_B = Table_A.Column_B
WHERE Table_A.Column_A = 1
FOR XML AUTO
END
ELSE
--Do something completely different
So... I'm getting the error that Table_A.Column_A is invalid, but how else can I make reference to it in my query? I've tried using dynamic SQL that creates the string up to the "FOR XML AUTO" part and using a stored procedure to tag the "FOR XML AUTO" part on afterwards, thinknig that might be the problem, but I get the same error.
To answer the questions I'm sure some people will ask, the query:
SELECT * FROM sysobjects o
JOIN syscolumns c
ON o.id = c.id
WHERE o.Name = 'Table_A'
AND c.Name = 'Column_A'
Yields no result, as you would expect when Column_A isn't in Table_A.
AND... No, I can't change the database structure instead, it has to be this workaround because the table may or may not contain this column, depending on the database instance, and I need a "catch-all"...
Any bright ideas?
The problem is that your code will not parse unless you have the column present in the data, because of the reference in the subquery. The if is evaluated at run-time. All the queries have to parse at compile-time.
The only way around this (that I know of) is dynamic SQL.
Here is a sample of code that does work:
declare #x xml;
declare #sql nvarchar(max) = '
select #x = (SELECT *
FROM INFORMATION_SCHEMA.tables t JOIN
INFORMATION_SCHEMA.COLUMNS c
ON t.TABLE_NAME = c.TABLE_NAME
WHERE t.TABLE_SCHEMA = ''dbo''
FOR XML AUTO
)';
exec sp_executesql #sql, N'#x xml output', #x = #x output;
select #x;
You can then place your if condition above it and modify it for your actual query.

get all table names with the primary key row count

I have a scenario, where I need to compare data between two servers.
Long story short, I need a result set which gives the output like
SchemaName|TableName|RowCount_PrimaryKey
Whenever a new student joins a unique schema is created say Stu1200 and this schema has 5 tables like
stu1200.class
stu1200.sub
stu1200.avg
stu1200.work
stu1200.blabla
There are 500 students in our database. So 500 schema. I need to compare all the tables of work of 500 students.
In order to do so I need to get the counts of the primary key, say StuID. So I need to get all the 500 schemas with the table like work.
Something like
SchemaName TableName StuID_Count
stu1200 Work 70
Stu1201 Work 112
Stu1202 Work 9
How can this be done? I have a script which does row counts of the table but its of useless, I need the row counts based only on the primary key.
Note: using SQL Server 2000 :(
Thanks in advance for sharing your suggestions/experience.
Your design is highly questionable but here is a way to get a relatively up-to-date count in an efficient manner. In SQL Server 2005+:
DECLARE #tablename SYSNAME;
SET #tablename = N'Work';
SELECT
SchemaName = OBJECT_SCHEMA_NAME([object_id]),
TableName = #tablename,
RowCount_PrimaryKey = SUM([rows])
FROM sys.partitions
WHERE OBJECT_NAME([object_id]) = #tablename
AND index_id IN (0,1)
GROUP BY OBJECT_SCHEMA_NAME([object_id])
ORDER BY SchemaName;
Just noticed SQL Server 2000.
DECLARE #tablename SYSNAME;
SET #tablename = N'Work';
SELECT
SchemaName = u.name,
TableName = #tablename,
i.rows
FROM
sys.sysindexes AS i
INNER JOIN sys.sysobjects AS o
ON i.id = o.id
INNER JOIN sys.sysusers AS u
ON o.uid = u.uid
WHERE i.indid IN (0,1)
AND o.name = #tablename;

How to find the name of stored procedure, based on table name search, using SQL Server 2008?

I want to find all of the stored procedures where a particular table is being used. There are lots of stored procedures in the database, so it's not feasible to check each procedure.
Is there any way to use a search query so that I can find the stored procedures?
I have tried this code:
SELECT distinct so.name
FROM syscomments sc
INNER JOIN sysobjects so ON sc.id=so.id
WHERE sc.TEXT LIKE '% RejectionReason %'
Where RejectionReason is my table name, but it shows all procedures where RejectionReason is used as column name, so that doesn't work.
SELECT o.name, o.type_desc, p.name, p.type_desc
FROM sys.sql_dependencies d
INNER JOIN sys.objects o
ON d.object_id = o.object_id
INNER JOIN sys.objects p
ON d.referenced_major_id = p.object_id
AND o.name = 'RejectionReason'
or
SELECT o.name, t.TABLE_NAME, c.text
FROM syscomments c
JOIN sysobjects o
ON c.id = o.id
JOIN INFORMATION_SCHEMA.Tables t
ON c.text LIKE '%RejectionReason%'
or
EXEC sp_depends #objname = N'RejectionReason';
if none of those help you check this blog:
http://blog.sqlauthority.com/2010/02/04/sql-server-get-the-list-of-object-dependencies-sp_depends-and-information_schema-routines-and-sys-dm_sql_referencing_entities/
Try to use RedGate's free tool SQL Search.
Here is a piece of code hope it will work. Just changes the table name it depends upon your code
SELECT DISTINCT so.name
FROM syscomments sc INNER JOIN sysobjects so on sc.id=so.id
WHERE sc.text LIKE '%tablename%'
e.g.:
SELECT DISTINCT so.name
FROM syscomments sc INNER JOIN sysobjects so on sc.id=so.id
WHERE sc.text LIKE '%users%'
You will get the list of store procedures and the table relations.
As per MSDN sp_depends will be removed in future releases in case you are using that, you can use the following query instead:
SELECT referencing_schema_name, referencing_entity_name, referencing_id, referencing_class_desc, is_caller_dependent
FROM sys.dm_sql_referencing_entities ('dbo.TableName', 'OBJECT');
There are two possibilities I am aware of.
Firstly SQL Management Studio has an option to show Dependencies. Right-click on the Table and select View Dependencies However, this will not highlight usps where the tablename is embedded in dynamic SQL.
The second option is to right click on the database and select Generate Scripts. Follow the wizard and script all the usps to a new query window, then search that for the name of your table. This is more laborious, but will find all uses.
I guess this script shows all the dependent object of the table, including SPs.
USE MYDatabase
GO
DECLARE #TableName varchar(100)
SET #TableName = 'mytable'
SELECT
SourceSchema = OBJECT_SCHEMA_NAME(sed.referencing_id)
,SourceObject = OBJECT_NAME(sed.referencing_id)
,ReferencedDB = ISNULL(sre.referenced_database_name, DB_NAME())
,ReferencedSchema = ISNULL(sre.referenced_schema_name,
OBJECT_SCHEMA_NAME(sed.referencing_id))
,ReferencedObject = sre.referenced_entity_name
,ReferencedColumnID = sre.referenced_minor_id
,ReferencedColumn = sre.referenced_minor_name
FROM sys.sql_expression_dependencies sed
CROSS APPLY sys.dm_sql_referenced_entities(OBJECT_SCHEMA_NAME(sed.referencing_id)
+ '.' + OBJECT_NAME(sed.referencing_id), 'OBJECT') sre
WHERE sed.referenced_entity_name = #TableName
AND sre.referenced_entity_name = #TableName
for more details you can check out.
http://sqlserverplanet.com/sql-server-2008/find-dependent-objects/
This will return SP's and Views.
SELECT DISTINCT o.name AS Object_Name,o.type_desc
FROM sys.sql_modules m
INNER JOIN sys.objects o
ON m.object_id=o.object_id
WHERE m.definition Like '%TableName%'
SysObjects stores basic information about all objects inside your database. It's useful for you to know because it tells us the name of each object and the type of the object.
SysComments stores the actual text (code) for your stored procedures and functions. It contains an ID field that maps back to the id field in SysObjects.
select so.name, text
from sysobjects so, syscomments sc
where so.id = sc.id
and text like '%RejectionReason%'
I am using the following SQL script to search for column names and text inside all stored procedures of your database. You can use it as well to find tables in stored procedures.
Specify the search term in variable #SearchFor(as you would use it in a LIKE expression, e.g. '%LastName%' to find columns and stored procedures containing LastName).
It will find column names in tables as well as text inside stored procedures. The script can even display the SP source code, if you set #SPNameOnlyto 0.
--
-- Purpose: Search field names in all tables, views stored procedures
--
DECLARE #SearchFor nvarchar(max)='%Search_SP_Or_Table_Or_View%' -- search for this string
DECLARE #SearchSP bit = 1 -- 1=search in SPs as well
DECLARE #DisplaySPSource bit = 1 -- 1=display SP source code
-- tables
if (#SearchSP=1) begin
(
select '['+c.table_Schema+'].['+c.table_Name+'].['+c.column_name+']' [schema_object],
t.table_type
from information_schema.columns c
left join information_schema.Tables t on c.table_name=t.table_name
where column_name like #SearchFor or t.table_name like #SearchFor
UNION
select '['+routine_Schema+'].['+routine_Name+']' [schema_object],
'PROCEDURE' as table_type from information_schema.routines
where routine_definition like #SearchFor or routine_name like #SearchFor
and routine_type='procedure'
)
order by table_type, schema_object
end else begin
select '['+c.table_Schema+'].['+c.table_Name+'].['+c.column_name+']' [schema_object],
t.table_type
from information_schema.columns c
left join information_schema.Tables t on c.table_name=t.table_name
where column_name like #SearchFor or t.table_name like #SearchFor
order by c.table_Name, c.column_name
end
-- stored procedure (source listing)
if (#SearchSP=1) begin
if (#DisplaySPSource=1) begin
select '['+routine_Schema+'].['+routine_Name+']' [schema.sp], routine_definition
from information_schema.routines
where routine_definition like #SearchFor or routine_name like #SearchFor
and routine_type='procedure'
order by routine_name
end
end