Count Stored Procedures in Database? - sql-server

How can i count the number of stored procedures in my database and is it a bad practice to have too many stored procedures?

Select count(*) from sysobjects where xtype = 'P'

Select count(1) from information_schema.routines
where routine_type = 'PROCEDURE'

you may want to exclude system stored procedures from your count
One way would be to call:
select count(*) from sysobjects
where xtype = 'P'
and category = 0
and left(name,2) <> 'sp'
That is assuming that you do not prefix your procedures with sp

You need as many as your application requires. Keeping procedures small and simple is a good thing.
If you're using sql 2005, a visual way to see your proc count is to navigate in SSMS to your stored procedure node under programmability. Click View-Object Explorer Details and a count of objects will be displayed on the right.

This will exclude the ones that sometimes get created when using the diagramming tool (they will start with dt_)
SELECT * FROM information_schema.routines
WHERE OBJECTPROPERTY(OBJECT_ID(SPECIFIC_NAME),'IsMSShipped') =1
AND routine_type = 'PROCEDURE'

Below is the query you can use:
select count(*) from sysobjects where xtype='P'
If all your db access is mandated to be through SP's, then the sky is the limit.

If you use them, then there really is no such thing as "too many".
I had a developer concerned his stored procs were using too much space in the database, so I had to actually calculate the total SIZE of all stored procs. Good answer for that here. The upshot was that the size of the stored procs together was responsible for maybe .001% of the total size of the database.

Here is a simple query you can use:
SELECT COUNT(object_id) FROM sys.procedures

With this query, you'll get the data amount of the actual text in all the procs in the DB.
The results is in bytes, so do the math for a MB results (1024*1024).
divide it by 1048576
SELECT SUM(DATALENGTH(sm.definition))/1048576 as 'Total Proc text size'
FROM sys.sql_modules sm
INNER JOIN sys.sysobjects so ON sm.object_id = so.id
WHERE so.type = 'P'

Related

Check if stored procedure modifies table data in SQL Server

I am granting a user group permissions to execute all stored procedures in a database which contain the word "Report" or "PDF", on the condition that the execution of these stored procedures will not modify the data in the database.
Now, I am currently reading through each of these stored procedures one at a time and basically doing a code review on each of them with the intention of determining if they modify data, or if they simply retrieve data.
Is there a programmatic way to test for the modification of the database in a single-run procedure that only gets run when the programmers want it run?
You can get this information from the sys.dm_sql_referenced_entities system function. is_updated will be 1 when any table is inserted, updated or deleted.
SELECT
schema_name = s.name,
p.name,
is_updated = CAST(
CASE WHEN EXISTS (SELECT 1
FROM sys.dm_sql_referenced_entities(QUOTENAME(s.name) + '.' + QUOTENAME(p.name), 'OBJECT') r
WHERE r.is_updated = 1)
THEN 1 ELSE 0 END
AS bit)
FROM sys.procedures p
JOIN sys.schemas s ON s.schema_id = p.schema_id
WHERE (p.name LIKE '%Report%' OR p.name LIKE '%PDF%')
AND p.is_ms_shipped = 0;
db<>fiddle
You can look for words like INSERT, UPDATE,DELETE... in the stored procedure code, here's an exmple of the query :
SELECT *
FROM sys.procedures
WHERE OBJECT_DEFINITION(OBJECT_ID) LIKE '%INSERT%'
OR OBJECT_DEFINITION(OBJECT_ID) LIKE '%UPDATE%'

Can and how do I use multiple databases at the same time in SQL with the USE statement?

My goal is to find the affected stored procedures across multiple databases when a table or view is updated. I am working in an environment with multiple databases where these stored procedures can exist. Below is a query that can do what I want for one database.
How can I achieve the results without having to change the USE statement to DatabaseB, DatabaseC, etc. or lengthy queries involving UNIONs?
USE DatabaseA
SELECT
O.name
, O.type_desc
, M.definition
FROM sys.sql_modules M
LEFT JOIN sys.objects O
ON O.object_id = M.object_id
WHERE 1=1
AND definition LIKE '%Error%'
I have played around with looping, but to no avail.
DECLARE name_Cursor CURSOR FOR
SELECT name
FROM master.dbo.sysdatabases
OPEN name_Cursor;
FETCH NEXT FROM name_Cursor;
WHILE ##FETCH_STATUS = 0
BEGIN
FETCH NEXT FROM name_Cursor;
END;
CLOSE name_Cursor;
DEALLOCATE name_Cursor;
GO
If you took your existing cursor (from your second code sample), and you plugged your query (from your first code sample) in as a dynamic query, it should work:
SET #SQL = '
USE ' + #DatabaseName + '
SELECT
O.name
...'
If you are wanting to run this query against ALL of your databases, a possibly easier solution would be to use the undocumented system stored procedure sp_msforeachdb.
I know you are reluctant to use a UNION, but it can be helpful for your situation. If you have the luxury of using Linked Servers, you can use a UNION with fully qualified paths. I would also recommend using INFORMATION_SCHEMA.ROUTINES if you can.
SELECT ROUTINE_NAME FROM [DB1].[dbo].INFORMATION_SCHEMA.ROUTINES WHERE ROUTINE_DEFINITION LIKE '%Error%'
UNION ALL
SELECT ROUTINE_NAME FROM [DB2].[dbo].INFORMATION_SCHEMA.ROUTINES WHERE ROUTINE_DEFINITION LIKE '%Error%'
You can also used a memory optimized table approach:
https://learn.microsoft.com/en-us/sql/relational-databases/in-memory-oltp/cross-database-queries
If you need to do something for each proc found, use this as the Cursor's SELECT statement.

Accessing the name of the currently executing stored procedure name via T-SQL?

I need to log the stored procedure name to determine which stored procedure are being used.
To accomplish this I am embedding an insert statement in each of the stored procedures we have to log it's usage.
I could hard code the SP name in the INSERT statement but I am looking for an elegant way to get the current stored procedure name rather than hard coding, this is primarily to be able to search for and remove identical lines of code after the project.
I have a table called tblUsed (ID INT, dateused date, sprocused varchar(50)) and was planning to do an insert in each query.
INSERT INTO [stockist].[dbo].[tblUsed]
([objectName])
VALUES
(*procname*)
I just need to get the name of the proc for this to work.
If there are any other ways to accomplish this I would be happy to hear them.
Thank you in advance.
Let's look at this from the ground up for you.
To get the name of the stored procedure you need to run the OBJECT_NAME(object_id [, database_id ]) metadata function(more info here). As you are running this T-SQL within the object in question, you won't need the database_id so the code you'll run will look something like this:
OBJECT_NAME(*object_id*)
To get the object id for the current T-SQL module you will need to use the ##PROCID metadata function(more info here) giving you the following code:
OBJECT_NAME(##PROCID)
In this case your INSERT statement will look like this:
INSERT INTO tblUsed (sprocused)
VALUES (OBJECT_NAME(##PROCID))
If you use multiple schema's you will probably need to be record which schema you are in using the OBJECT_SCHEMA(object_id [, database_id ]) metadata function(more info here) giving you this:
OBJECT_SCHEMA_NAME(##PROCID) + '.' + OBJECT_NAME(##PROCID)
In this case your INSERT statement will look like this:
INSERT INTO tblUsed (sprocused)
VALUES (OBJECT_SCHEMA_NAME(##PROCID) + '.' + OBJECT_NAME(##PROCID))
One other possible way to accomplish this without all the overhead of an unnecessary insert in all your queries is through the use of DMVs(Dynamic management views) here is a sample query (from this SO thread)
SELECT sc.name
, p.name
FROM sys.procedures AS p
INNER JOIN sys.schemas AS sc
ON p.[schema_id] = sc.[schema_id]
LEFT OUTER JOIN sys.dm_exec_procedure_stats AS st
ON p.[object_id] = st.[object_id]
WHERE st.[object_id] IS NULL
ORDER BY p.name;
NB: This will only give you the information from the last time SQL was restarted.
As a result of this question you might want to ensure that none of your procs are referenced anywhere else in the db you can do this like so:
SELECT referencing_schema_name
, referencing_entity_name
FROM sys.dm_sql_referencing_entities ('*schemaname.objectname*', 'OBJECT');

How to see which stored procedures are affected by changing schema name

I am in the process of changing the schema of a couple of tables. Currently all the tables are in the dbo schema and need to be moved into a different schema.
I have run the following script ( on many tables):
ALTER SCHEMA client TRANSFER dbo.Companies
The issue I have now is that there are stored procedures that ned to be updated to use the correct table name
dbo.Companies -> client.Companies
Is there any way one can check which stored procedures need to be checked and fixed?
There might be a best method since this one needs some manual editing but here is what I would do.
I have a small query that lets me search stored procedure for a string.
SELECT
sysobjects.name
,sysobjects.id
,sysobjects.xtype
FROM
sysobjects
INNER JOIN
syscomments
ON
sysobjects.id = syscomments.id
WHERE
syscomments.text LIKE '%dbo.Companies%'
GROUP BY
sysobjects.name
,sysobjects.id
,sysobjects.xtype
order by
sysobjects.name
The query will give you the name, id and xtype of all stored procedures containing dbo.Companies. If you change the WHERE-clause to look for all the tables you moved to the other scheme you will (hopefully :) ) get a list of all stored procedures you need to update.
If you want you can probably modify the query and update the stored procedure body with REPLACE and have it all automated. But make sure the query gives you the correct results first. I did not use it for this use case, I simply use it to search for text in stored procedure but theoretically it should work.
This will give you all objects that depend on dbo.companies. Please do remember that you will also need to change functions, views and other objects as well, apart from the stored procedures.
SELECT Db_name() referencing_database_name,
Object_name (referencing_id) referencing_entity_name,
Isnull(referenced_schema_name, 'dbo') referenced_schema_name,
referenced_entity_name,
ao.type_desc referenced_entity_type,
Isnull(referenced_database_name, Db_name()) referenced_database_name
FROM sys.sql_expression_dependencies sed
JOIN sys.all_objects ao
ON sed.referenced_entity_name = ao.name
WHERE sed.referenced_schema_name='dbo' AND sed.referenced_entity_name='Companies'
following are the way can check the depedencies
Method 1: Using sp_depends
sp_depends 'dbo.First'
GO
Method 2: Using information_schema.routines
SELECT *
FROM information_schema.routines ISR
WHERE CHARINDEX('dbo.First', ISR.ROUTINE_DEFINITION) > 0
GO
Method 3: Using DMV sys.dm_sql_referencing_entities
SELECT referencing_schema_name, referencing_entity_name,
referencing_id, referencing_class_desc, is_caller_dependent
FROM sys.dm_sql_referencing_entities ('dbo.First', 'OBJECT');
GO

getting schema + first 100 records from every table in a db

i have a large sql server db, and i want to get the schema (all tables/triggers/sprocs), i'm pretty sure that's easy.
but the tough part is that i want to get 100 records from each table. it's a huge db on a remote server and i can't develop locally without a mockup copy.
thanks for your help!
To get the schema, basically just select everything from the sys.objects catalog view:
SELECT * FROM sys.objects
For the data: you could use the undocumented (but extremely helpful) stored procedure sp_MSForEachTable for that purpose:
exec sp_MSforeachtable 'select top 100 * from ? '
I would create a cursor with sys.objects to get the user defined tables and populate the new database with select query of top 100 rows.
Make sure you have (NOLOCK) hint to your query, so that it can avoid locks

Resources