I have a huge database with 100's of tables and stored procedures. Using SQL Server 2005, how can I get a list of stored procedures that are doing an insert or update operation on a given table.
sys.sql_dependencies has a list of entities with dependencies, including tables and columns that a sproc includes in queries. See this post for an example of a query that gets out dependencies. The code snippet below will get a list of table/column dependencies by stored procedure
select sp.name as sproc_name
,t.name as table_name
,c.name as column_name
from sys.sql_dependencies d
join sys.objects t
on t.object_id = d.referenced_major_id
join sys.objects sp
on sp.object_id = d.object_id
join sys.columns c
on c.object_id = t.object_id
and c.column_id = d.referenced_minor_id
where sp.type = 'P'
select
so.name,
sc.text
from
sysobjects so inner join syscomments sc on so.id = sc.id
where
sc.text like '%INSERT INTO xyz%'
or sc.text like '%UPDATE xyz%'
This will give you a list of all stored procedure contents with INSERT or UPDATE in them for a particular table (you can obviously tweak the query to suit). Also longer procedures will be broken across multiple rows in the returned recordset so you may need to do a bit of manual sifting through the results.
Edit: Tweaked query to return SP name as well. Also, note the above query will return any UDFs as well as SPs.
Use sys.dm_sql_referencing_entities
Note that sp_depends is obsoleted.
MSDN Reference
You could try exporting all of your stored procedures into a text file and then use a simple search.
A more advanced technique would be to use a regexp search to find all SELECT FROM and INSERT FROM entries.
If you download sp_search_code from Vyaskn's website it will allow you to find any text within your database objects.
http://vyaskn.tripod.com/sql_server_search_stored_procedure_code.htm
This seems to work:
select
so.name as [proc],
so2.name as [table],
sd.is_updated
from sysobjects so
inner join sys.sql_dependencies sd on so.id = sd.object_id
inner join sysobjects so2 on sd.referenced_major_id = so2.id
where so.xtype = 'p' -- procedure
and is_updated = 1 -- proc updates table, or at least, I think that's what this means
SELECT Distinct SO.Name
FROM sysobjects SO (NOLOCK)
INNER JOIN syscomments SC (NOLOCK) on SO.Id = SC.ID
AND SO.Type = 'P'
AND (SC.Text LIKE '%UPDATE%' OR SC.Text LIKE '%INSERT%')
ORDER BY SO.Name
This link was used as a resource for the SP search.
Related
I am aware of this query that can pull referenced tables from a SQL Server stored procedure.
For example, if I have this stored procedure:
UPDATE tbl1
SET symbol = tbl2.symbol, symbol2 = tbl2.symbol2
FROM tbl1
JOIN tbl2 ON tbl1.PK = tbl2.PK
This query:
SELECT Name
FROM sys.procedures
WHERE OBJECT_DEFINITION(OBJECT_ID) LIKE '%TableNameOrWhatever%'
and this one:
SELECT
o.name
FROM
sys.sql_modules sm
INNER JOIN sys.objects o ON
o.object_id = sm.object_id
WHERE
sm.definition LIKE '%<table name>%'
both return tbl1 & tbl2 as the response.
My question is this: tb11 is ReadWrite as the SQL shows, and tbl2 is ReadOnly.
How do I update my queries to make the distinction?
So my output should be:
Response
========
tbl1, ReadWrite
tbl2, ReadOnly
Thanks!
Try sys.sql_dependencies, eg
select object_name(d.referenced_major_id) referenced_object,
object_name(d.object_id) referenced_by,
max(cast(d.is_updated as int)) is_updated
from sys.sql_dependencies d
join sys.objects o
on d.object_id = o.object_id
where o.type_desc = 'SQL_STORED_PROCEDURE'
group by d.referenced_major_id, d.object_id
order by d.object_id
But beware that procedures with deferred name resolution and stored procedures that access tables with dynamic SQL won't be tracked
The DMV sys.dm_sql_referenced_entities contains this information.
The following query should get you exactly what you need
SELECT
name,
referenced_entity_name,
is_updated
FROM sys.procedures p
CROSS APPLY sys.dm_sql_referenced_entities(SCHEMA_NAME(p.schema_id) + '.' + p.name,'OBJECT') r
WHERE referenced_minor_name IS NULL;
db<>fiddle
I've been playing around with some queries involving Metadata (hopefully, I'm using the correct terminology) and one of the thing I did was to return all the tables created by the current user, using the database.
This is the script:
SELECT so.name as [Table], su.name as [User]
FROM sysobjects so
INNER JOIN sysusers su
ON so.uid = su.uid
WHERE xtype = 'U' -- user-defined table
AND su.name=USER_NAME()
Then I read that sysobjects is in the system only for backward compatibility with SQL Server 2000, and one must use sys.objects instead. Well, I tried to change the code, but sys.objects doesn't has a column with information related to the user (sysobjects has the column uid) who created the listed objects.
How can I replace sysobjects above by sys.objects?
Use the sys.objects table. The principal_id column contains the value you want:
principal_id - ID of the individual owner, if different from the
schema owner. By default, schema-contained objects are owned by the
schema owner. However, an alternate owner can be specified by using
the ALTER AUTHORIZATION statement to change ownership.
Source: sys.objects documentation.
Try this query:
SELECT t.name AS Table_Name
,t.principal_id AS Table_Owner_User_Id
,s.schema_id
,s.name AS Schema_Name
,s.principal_id AS Schema_Owner_User_Id
FROM sys.objects t
INNER JOIN sys.schemas s
ON t.schema_id = s.schema_id
WHERE t.type = 'U'
AND COALESCE(t.principal_id, s.principal_id) = USER_ID()
-- Or, if you must use USER_NAME(), then use the following instead:
--AND USER_NAME(COALESCE(t.principal_id, s.principal_id)) = USER_NAME()
The code below displays, among other things, the source code for all the triggers in a database
SELECT so.name AS trigger_name,
s.name AS table_schema,
t.name AS table_name,
LEN (sc.[text]) as len,
sc.[text] AS trigger_content
FROM [GDI-193-DEV].dbo.sysobjects so
INNER JOIN [GDI-193-DEV].sys.tables t ON so.parent_obj = t.object_id
INNER JOIN [GDI-193-DEV].sys.schemas s ON t.schema_id = s.schema_id
INNER JOIN [GDI-193-DEV].sys.syscomments sc ON so.id = sc.id
WHERE so.type = 'TR'
The problem is if the length of the trigger source code is more than 4,000 characters it ends up spanning two records in sys.syscomments.
So, for example, if the trigger source is 4,700 characters it will be spread across 2 records in sys.syscomments. sys.syscomments.TEXT in the first record will have a length of 4,000 while the remaining 700 characters will be put into another record.
This is causing problems for me as I am trying to compare the complete trigger source code between two databases.
This seem like some strange behavior. Am I missing something? Is there a different way of getting the source code that avoids this problem?
Thanks in advance,
I had the same problem, and found out that there's another way to get untrimmed definitions. Try if entire code of your trigger shows, and then you can work your way to joinning this to other system tables/views:
select top 100
*
from sys.sql_modules
where 1=1
and definition like '%trigger%'
Try using object_definition like this:
SELECT so.name AS trigger_name,
s.name AS table_schema,
t.name AS table_name,
object_definition(so.object_id) AS trigger_content
FROM [GDI-193-DEV].dbo.sysobjects so
INNER JOIN [GDI-193-DEV].sys.tables t ON so.parent_obj = t.object_id
INNER JOIN [GDI-193-DEV].sys.schemas s ON t.schema_id = s.schema_id
WHERE so.type = 'TR'
I'm using the following t-sql code:
USE [my_database]
SELECT DISTINCT so.name
FROM syscomments sc
INNER JOIN sysobjects so ON sc.id=so.id
WHERE sc.TEXT LIKE '%table_name%'
in order to show all the Stored Procedures that use the table table_name.
I want do this work for all tables in my database.
How can I perform this task and organize the output?
This uses information schema for both tables, and stored procedures. You can change or get rid of ROUTINE_TYPE condition to add functions, and you can change table type to return views.
This answer produces its results by checking what tables a stored procedure depends on. I think this will be a much more accurate result then checking if a name is in the query text. If the procedure refers to a table in a comment section, then this result will not be returned in the first query, but will be in the second and other answers given.
SELECT t.TABLE_NAME, s.ROUTINE_NAME
FROM INFORMATION_SCHEMA.TABLES t
INNER JOIN INFORMATION_SCHEMA.ROUTINES s ON
s.ROUTINE_NAME IN (SELECT referencing_entity_name
FROM sys.dm_sql_referencing_entities(TABLE_SCHEMA + '.' + TABLE_NAME, 'OBJECT'))
AND s.ROUTINE_TYPE = 'PROCEDURE'
WHERE t.TABLE_TYPE = 'BASE TABLE'
edit: Here's how to get the dependencies without the function. (I like this method the best)
SELECT DISTINCT t.name [TableName], p.name [ProcedureName]
FROM sys.objects t
LEFT JOIN sys.sql_dependencies d ON
d.referenced_major_id = t.object_id
LEFT JOIN sys.objects p ON
p.object_id = d.object_id
AND p.type = 'p'
WHERE t.type = 'u'
If your specific use is to just find any string that matches a table name, below will work:
SELECT t.TABLE_NAME, s.ROUTINE_NAME
FROM INFORMATION_SCHEMA.TABLES t
INNER JOIN INFORMATION_SCHEMA.ROUTINES s
ON CHARINDEX(t.TABLE_NAME, s.ROUTINE_DEFINITION) > 0
AND s.ROUTINE_TYPE = 'PROCEDURE'
WHERE t.TABLE_TYPE = 'BASE TABLE'
You could do a JOIN on LIKE:
select * from INFORMATION_SCHEMA.TABLES t
join
(
SELECT DISTINCT so.name
FROM syscomments sc
INNER JOIN sysobjects so ON sc.id=so.id
) x on x.name like '%' + t.TABLE_NAME + '%'
Note that your query doesn't restrict to procs - you'll also get views, defaults, and other objects too. If you just want procs, you can add where so.xtype = 'P' to your inner query.
Another version that uses sys tables only:
select t.name as TableName, p.name as SPName
from sys.objects t
join sys.syscomments c
on c.text like '%' + t.name + '%'
join sys.objects p
on p.object_id = c.id
where t.type = 'U' -- user table
and p.type = 'P' -- procedure
You can also use the built in function that's been around at least since SQL 2005 and works for tables, views, and stored procedures. I get the same number of results as Daniel's answer above when checking dependencies on a table in a fairly enterprisy database.
sp_depends [TableName]
sp_depends [TableName.Column]
sp_depends [StoredProcedureName]
http://msdn.microsoft.com/en-us/library/ms189487(v=sql.90).aspx
To discover all triggers in any given MS SQL Server database, I'm currently querying the sysobjects table (which is fine because it works in MS SQL Server 2000 which I have to support) e.g.
SELECT R1.name AS trigger_name,
T1.name AS trigger_parent_table_name
FROM sysobjects AS R1
INNER join sysobjects AS T1
ON R1.parent_obj = T1.id
WHERE R1.xtype = 'tr';
This gives me a reduced list of trigger names and for each I can use
EXEC sp_helptext 'trigger_name_here'
to find the definition. That works fine for databases where only the default dbo schema is used.
I now have a MS SQL Server 2005 database which uses multiple schemas. What is the best way of discovering the schema for each trigger?
You are looking for the parent object for a trigger so it will always be a table. In sys.tables (system view) you get the schema_id and with it you can go sys.schemas (system view too) to get the schema's name.
Hope this helps.
--
EDIT:
The code:
SELECT sys.objects.name AS [trigger],
sys.tables.name AS [table],
sys.objects.type,
sys.schemas.name AS [schema]
FROM sys.schemas RIGHT OUTER JOIN
sys.tables ON sys.schemas.schema_id = sys.tables.schema_id RIGHT OUTER JOIN
sys.objects ON sys.tables.object_id = sys.objects.parent_object_id
WHERE sys.objects.type = 'tr'
This is is with sys.tables but you can do it with only sys.objects, this is a general select to look for parents and schemas:
SELECT O.name, O.type, S.name AS [schema],
OP.name AS parent_name, OP.type AS parent_type, SP.name AS parent_schema
FROM sys.schemas AS SP RIGHT OUTER JOIN
sys.objects AS OP ON SP.schema_id = OP.schema_id RIGHT OUTER JOIN
sys.objects AS O LEFT OUTER JOIN
sys.schemas AS S ON O.schema_id = S.schema_id ON OP.object_id = O.parent_object_id