I need to create a variable that lists all the existing databases in my system, because I need it and I don't know how to do it. I have tried to create variables like this one:
DECLARE #nombreBD INT;
SET #nombreBD = (SELECT [database_id] FROM sys.databases Where name = 'model' )
SELECT #nombreBD AS Database_ID
PRINT #nombreBD
GO
This variable gets me only the name I put in the "WHERE" parameter but I need to get them all.
The table sys.databases shows you all the existing databases in the system and I need to get a boolean value from it, I thought to get it from the column "database_id" that's why I declared this variable.
This creates a table name #DBList with a column nombreBD
and inserts the database_id to the column,
then it shows all your sql-server database database_id
BEGIN
DECLARE #DBList TABLE (nombreBD INT)
INSERT INTO #DBList(nombreBD) SELECT database_id FROM sys.databases
SELECT * FROM #DBList
END
Is that what you need ?
To achieve what you want, you will need to use some dynamic SQL. Something like this ought to work for your case:
DECLARE #DBList TABLE (nombre varchar(50));
INSERT INTO #DBList(nombre) SELECT name FROM sys.databases
WHERE name NOT IN ('master','tempdb','msdb');
declare #name nvarchar(50);
declare #sql nvarchar(2000);
DECLARE db_Cursor CURSOR FOR
SELECT nombre FROM #DBList;
OPEN db_Cursor;
FETCH NEXT FROM db_Cursor INTO #name;
WHILE ##FETCH_STATUS = 0
BEGIN
SET #sql = N'USE ' + #name + N';'
exec sp_executesql #sql;
SET #sql = N'SELECT DB_NAME() AS DatabaseName, ''guest'' AS Database_User, [permission_name], [state_desc]
FROM sys.database_permissions WHERE [grantee_principal_id] = DATABASE_PRINCIPAL_ID(''guest'') AND [state_desc] LIKE ''GRANT%'' AND [permission_name] = ''CONNECT'';';
exec sp_executesql #sql;
FETCH NEXT FROM db_Cursor INTO #name;
END;
CLOSE db_Cursor;
DEALLOCATE db_Cursor;
Notice that I have changed the table variable to hold the database names, not their ids. This is because the USE statement takes the name not the id.
The cursor loops through the values, builds the various sql statements and executes them.
I am using the stored procedure shown here for taking backups of databases from SQL Server.
It takes all backups for around 20 databases, now I want little change in the stored procedure.
It want below databases backups to pick through loop, how to modify existing stored procedure. Thanks
Emp_DB
Salary_DB
Company_DB
Attendance_DB
Code:
CREATE PROCEDURE Backupdbs
AS
BEGIN
DECLARE c1 CURSOR FOR
SELECT name FROM sys.databases WHERE database_id > 4
DECLARE #dbname varchar(100)
DECLARE #fname varchar(100)
OPEN C1
FETCH NEXT FROM c1 INTO #dbname
WHILE (##fetch_status = 0)
-- here, you're missing a
-- BEGIN
SET #fname = 'D:\Backup\'+#dbname+'.bak'
BACKUP DATABASE #dbname TO disk=#fname
FETCH NEXT FROM cl INTO #dbname
END
CLOSE c1
DEALLOCATE c1
END IF
Thanks
mg
A better scalable solution would be to have your own list of database names you want to back up, possibly with a groupId.
You can then pass a #groupId parameter and run a batch of database backups for the group or set of databases you choose - eg you can group large databases together, small together, frequently modified etc
So for example you could have the following table
create table BackupSets (
id int identity(1,1) primary key,
GroupId int,
[Name] sysname
)
and use it instead of sys.databases
select [Name] from BackupSets where groupId=#GroupId
You could also have a process as part of your backup to check for any names in sys.databases that don't exist in your list and insert them.
You could just add the databases in question to your where clause in your cursor query against sys.databases.
CREATE PROCEDURE Backupdbs
AS
BEGIN
DECLARE c1 CURSOR FOR
SELECT name FROM sys.databases WHERE database_id > 4
and name IN ('Emp_DB','Salary_DB','Company_DB','Attendance_DB')
DECLARE #dbname varchar(100)
DECLARE #fname varchar(100)
OPEN C1
FETCH NEXT FROM c1 INTO #dbname
WHILE (##fetch_status = 0)
-- here, you're missing a
-- BEGIN
SET #fname = 'D:\Backup\'+#dbname+'.bak'
BACKUP DATABASE #dbname TO disk=#fname
FETCH NEXT FROM cl INTO #dbname
END
CLOSE c1
DEALLOCATE c1
END IF
I've developed the following script:
declare #query nvarchar(1000)
declare #Loop int
declare #Whse table
( ID int identity primary key
, WhseLink int)
insert into #Whse
( WhseLink )
select WhseLink from WhseMst
select #Loop = min(ID) from #Whse
while #Loop is not null
begin
set #query = 'exec _bspWhUtilAddAllStkToWh('+cast((select WhseLink from #Whse where ID = #Loop) as varchar)+')'
exec #query
select #Loop = min(ID) from #Whse where ID>#Loop
end
Based on the above, I get the following Error:
Could not find stored procedure 'exec _bspWhUtilAddAllStkToWh 2'
I've checked the following Link which the user also had the same problem, but I think this one is different to that, due to the fact that the Stored Procedure actually exists and when I run the same script separately, it works.
I've tried adding brackets so that the #query eventually looks like this : 'exec (_bspWhUtilAddAllStkToWh) 2', but I still receive the same error.
What am I missing?
Ideally you should avoid looping at all costs. In your situation I would consider changing your procedure to receive a table valued function so you can receive a whole collection of Warehouse Links and do whatever is in your procedure on the entire set. But assuming you can't do that you can use a cursor here and forget the dynamic sql because it isn't needed.
Something like this is a lot simpler.
declare #WarehouseLink int
declare Warehouses cursor local fast_forward
for
select WhseLink
from WhseMst
fetch next from Warehouses into #WarehouseLink
while ##FETCH_STATUS = 0
begin
exec _bspWhUtilAddAllStkToWh #WarehouseLink
fetch next from Warehouses into #WarehouseLink
end
I have a table that stores names of stored procedures in my file structure. The idea is that the calling stored procedure will be given #in_Strings as a parameter; these are the display names of the stored procedures I want to execute.
Then, I want to search my table of stored procedures and execute the ones whose display names match with the inputted set.
For example, the calling stored procedure may be given an input set of strings 'foo', 'bar', and 'baz'. That means I want to be able to execute 'dbo.foo_sproc','dbo.bar_sproc', and 'dbo.baz_sproc'.
I am using SQL Server 2012. Any ideas?
BTW, my stored procedures table looks like this:
CREATE TABLE dbo.SPROCS
(
Display_Name NVARCHAR(256) NOT NULL,
SPROC_Name NVARCHAR(256) NOT NULL,
CreatedDateTime DATETIME2(2) NOT NULL DEFAULT GETUTCDATE()
)
You can use dynamic SQL, like in paqogomez's answer, but, unlike any other kind of names, procedure names can be parametrised in SQL Server, and so dynamic SQL is not necessary in this case.
For instance, if this was about a single procedure, you could read and execute the matching name using this simple method:
DECLARE #SPROC_Name nvarchar(256);
SELECT #SPROC_Name = SPROC_Name
FROM dbo.SPROCS
WHERE Display_Name = #in_string;
EXECUTE #SPROC_Name;
Just like that.
Since you are mentioning a set of strings, however, you will need a cursor to loop through the result set of matching procedure names and pass each name to the EXECUTE statement.
DECLARE #SPROC_Name nvarchar(256);
DECLARE procnames CURSOR
LOCAL FORWARD_ONLY STATIC READ_ONLY
FOR
SELECT #SPROC_Name = SPROC_Name
FROM dbo.SPROCS
WHERE ... /* condition involving Display_Name and #in_string */
;
OPEN procnames;
FETCH NEXT FROM procnames INTO #SPROC_Name;
WHILE ##FETCH_STATUS = 0
BEGIN
EXECUTE #SPROC_Name;
FETCH NEXT FROM procnames INTO #SPROC_Name;
END;
CLOSE procnames;
DEALLOCATE procnames;
A sql server example:
A cursor can loop through your result set and execute your stored procedures.
This (simple, but untested) script loops every sproc in the #in_strings variable.
CREATE PROCEDURE getSprocs #in_Strings varchar(max)
AS
BEGIN
DECLARE #sql varchar(max)
DECLARE db_cursor CURSOR FOR
SELECT SPROC_Name
FROM dbo.SPROCS
where sproc_name in (#in_Strings)
OPEN db_cursor
FETCH NEXT FROM db_cursor INTO #name
WHILE ##FETCH_STATUS = 0
BEGIN
set #sql = 'exec ' + #name
exec #sql
FETCH NEXT FROM db_cursor INTO #name
END
CLOSE db_cursor
DEALLOCATE db_cursor
END
i want to ensure that all stored procedures are still syntactically valid. (This can happen if someone renames/deletes a table/column).
Right now my solution to check the syntax of all stored procedures is to go into Enterprise Manager, select the first stored procedure in the list, and use the procedure:
Enter
Alt+C
Escape
Escape
Down Arrow
Goto 1
It works, but it's pretty tedious. i'd like a stored procedure called
SyntaxCheckAllStoredProcedures
like the other stored procedure i wrote that does the same thing for views:
RefreshAllViews
For everyone's benefit, RefreshAllViews:
RefreshAllViews.prc
CREATE PROCEDURE dbo.RefreshAllViews AS
-- This sp will refresh all views in the catalog.
-- It enumerates all views, and runs sp_refreshview for each of them
DECLARE abc CURSOR FOR
SELECT TABLE_NAME AS ViewName
FROM INFORMATION_SCHEMA.VIEWS
OPEN abc
DECLARE #ViewName varchar(128)
-- Build select string
DECLARE #SQLString nvarchar(2048)
FETCH NEXT FROM abc
INTO #ViewName
WHILE ##FETCH_STATUS = 0
BEGIN
SET #SQLString = 'EXECUTE sp_RefreshView '+#ViewName
PRINT #SQLString
EXECUTE sp_ExecuteSQL #SQLString
FETCH NEXT FROM abc
INTO #ViewName
END
CLOSE abc
DEALLOCATE abc
For everyone's benefit, a stored procedure to mark all stored procedure as needing a recompile (marking a stored procedure for recompile will not tell you if it's syntactically valid):
RecompileAllStoredProcedures.prc
CREATE PROCEDURE dbo.RecompileAllStoredProcedures AS
DECLARE abc CURSOR FOR
SELECT ROUTINE_NAME
FROM INFORMATION_SCHEMA.routines
WHERE ROUTINE_TYPE = 'PROCEDURE'
OPEN abc
DECLARE #RoutineName varchar(128)
-- Build select string once
DECLARE #SQLString nvarchar(2048)
FETCH NEXT FROM abc
INTO #RoutineName
WHILE ##FETCH_STATUS = 0
BEGIN
SET #SQLString = 'EXECUTE sp_recompile '+#RoutineName
PRINT #SQLString
EXECUTE sp_ExecuteSQL #SQLString
FETCH NEXT FROM abc
INTO #RoutineName
END
CLOSE abc
DEALLOCATE abc
For completeness sake, the UpdateAllStatistics procedure. This will update all statistics in the database by doing a full data scan:
RefreshAllStatistics.prc
CREATE PROCEDURE dbo.RefreshAllStatistics AS
EXECUTE sp_msForEachTable 'UPDATE STATISTICS ? WITH FULLSCAN'
You can also do this "in-place" - without getting all the create statements.
In addition to setting NOEXEC ON, you will also need to set your favorite SHOWPLAN_* ON (I use SHOWPLAN_TEXT). Now you can get rid of your step 2 and just execute each procedure you retrieved in step 1.
Here is a sample using an individual stored procedure. You can work it into your favorite loop:
create procedure tests #bob int as
select * from missing_table_or_view
go
set showplan_text on;
go
set noexec on
exec tests
set noexec off
go
set showplan_text off;
go
drop procedure tests
go
The above sample should generate the following output:
Msg 208, Level 16, State 1, Procedure tests, Line 2
Invalid object name 'missing_table_or_view'.
The check suggested by KenJ is definitely the best one, since the recreate/alter-approaches does not find all errors. E.g.
impossible execution plans due to query-hints
I even had an SP referencing a non-existing table that went through without the error being detected.
Please find my version that checks all existing SPs at once with KenJ's method below. AFAIK, it will detect every error that will keep the SP from being executed.
--Forces the creation of execution-plans for all sps.
--To achieve this, a temporary SP is created that calls all existing SPs.
--It seems like the simulation of the parameters is not necessary. That makes things a lot easier.
DECLARE #stmt NVARCHAR(MAX) = 'CREATE PROCEDURE pTempCompileTest AS ' + CHAR(13) + CHAR(10)
SELECT #stmt = #stmt + 'EXEC [' + schemas.name + '].[' + procedures.name + '];'
FROM sys.procedures
INNER JOIN sys.schemas ON schemas.schema_id = procedures.schema_id
WHERE schemas.name = 'dbo'
ORDER BY procedures.name
EXEC sp_executesql #stmt
GO
--Here, the real magic happens.
--In order to display as many errors as possible, XACT_ABORT is turned off.
--Unfortunately, for some errors, the execution stops anyway.
SET XACT_ABORT OFF
GO
--Showplan disables the actual execution, but forces t-sql to create execution-plans for every statement.
--This is the core of the whole thing!
SET SHOWPLAN_ALL ON
GO
--You cannot use dynamic SQL in here, since sp_executesql will not be executed, but only show the string passed in in the execution-plan
EXEC pTempCompileTest
GO
SET SHOWPLAN_ALL OFF
GO
SET XACT_ABORT ON
GO
--drop temp sp again
DROP PROCEDURE pTempCompileTest
--If you have any errors in the messages-window now, you should fix these...
If you are using sql 2008 r2 or below then do not use
SET NOEXEC ON
It only checks the syntax and not for potential errors like the existence of tables or columns.
Instead use:
SET FMTONLY ON
it will do a full compile as it tries to return the meta data of the stored procedure.
For 2012 and you will need to use stored procedure:
sp_describe_first_result_set
Also you can do a complete script in Tsql that checks all sp and views, its just a bit of work.
UPDATE
I wrote a complete solution for in tsql that goes through all user defined stored proceedures and checks there syntax. the script is long winded but can be found here http://chocosmith.wordpress.com/2012/12/07/tsql-recompile-all-views-and-stored-proceedures-and-check-for-error/
In addition you might want to consider using Visual Studio Team System 2008 Database Edition which, among other things, does a static verification of all stored procedures in the project on build, thus ensuring that all are consistent with the current schema.
I know this is way old, but I created a slightly different version that actually re-creates all stored procedures, thus throwing errors if they cannot compile. This is something you do not achieve by using the SP_Recompile command.
CREATE PROCEDURE dbo.UTL_ForceSPRecompilation
(
#Verbose BIT = 0
)
AS
BEGIN
--Forces all stored procedures to recompile, thereby checking syntax validity.
DECLARE #SQL NVARCHAR(MAX)
DECLARE #SPName NVARCHAR(255)
DECLARE abc CURSOR FOR
SELECT NAME, OBJECT_DEFINITION(o.[object_id])
FROM sys.objects AS o
WHERE o.[type] = 'P'
ORDER BY o.[name]
OPEN abc
FETCH NEXT FROM abc
INTO #SPName, #SQL
WHILE ##FETCH_STATUS = 0
BEGIN
--This changes "CREATE PROCEDURE" to "ALTER PROCEDURE"
SET #SQL = 'ALTER ' + RIGHT(#SQL, LEN(#SQL) - (CHARINDEX('CREATE', #SQL) + 6))
IF #Verbose <> 0 PRINT #SPName
EXEC(#SQL)
FETCH NEXT FROM abc
INTO #SPName, #SQL
END
CLOSE abc
DEALLOCATE abc
END
I know this is a old question but this is my solution when I could not find any suiting.
I required to validate my stored procedures and views after alot of changes in the database.
Basicly what i wanted was to try to do a ALTER PROCEDURE and ALTER VIEW using the current procedures and view (not actually changing them).
I have written this that works fairly well.
Note! Do not perform on live database, make a copy to validate and then fix the things need fixing. Also sys.sql_modules can be inconsistent so take extra care. I do not use this to actually make the changes, only to check which are not working properly.
DECLARE #scripts TABLE
(
Name NVARCHAR(MAX),
Command NVARCHAR(MAX),
[Type] NVARCHAR(1)
)
DECLARE #name NVARCHAR(MAX), -- Name of procedure or view
#command NVARCHAR(MAX), -- Command or part of command stored in syscomments
#type NVARCHAR(1) -- Procedure or view
INSERT INTO #scripts(Name, Command, [Type])
SELECT P.name, M.definition, 'P' FROM sys.procedures P
JOIN sys.sql_modules M ON P.object_id = M.object_id
INSERT INTO #scripts(Name, Command, [Type])
SELECT V.name, M.definition, 'V' FROM sys.views V
JOIN sys.sql_modules M ON V.object_id = M.object_id
DECLARE curs CURSOR FOR
SELECT Name, Command, [Type] FROM #scripts
OPEN curs
FETCH NEXT FROM curs
INTO #name, #command, #type
WHILE ##FETCH_STATUS = 0
BEGIN
BEGIN TRY
IF #type = 'P'
SET #command = REPLACE(#command, 'CREATE PROCEDURE', 'ALTER PROCEDURE')
ELSE
SET #command = REPLACE(#command, 'CREATE VIEW', 'ALTER VIEW')
EXEC sp_executesql #command
PRINT #name + ' - OK'
END TRY
BEGIN CATCH
PRINT #name + ' - FAILED: ' + CAST(ERROR_NUMBER() AS NVARCHAR(MAX)) + ' ' + ERROR_MESSAGE()
--PRINT #command
END CATCH
FETCH NEXT FROM curs
INTO #name, #command, #type
END
CLOSE curs
A bit of a drawn-out option:
Create a copy of the database
(backup and restore). You could do this on the target database, if your confidence level is high.
Use SSMS to script out all the
stored procedures into a single script file
DROP all the procedures
Run the script to recreate them. Any that can't be created will error out.
Couple of fussy gotchas in here, such as:
You want to have the "if proc exists
then drop proc GO create proc ... GO"
syntax to separte each procedure.
Nested procedures will fail if they
call a proc that has not yet been
(re)created. Running the script several
times should catch that (since
ordering them properly can be a real
pain).
Other and more obscure issues might crop up, so be wary.
To quickly drop 10 or 1000 procedures, run
SELECT 'DROP PROCEDURE ' + schema_name(schema_id) + '.' + name
from sys.procedures
select the output, and run it.
This assumes you're doing a very infrequent task. If you have to do this regularly (daily, weekly...), please let us know why!
There is no way to do it from T-SQL, or Enterprise Manager, so i had to write something from client code. i won't post all the code here, but the trick is to:
1) Get a list of all stored procedures
SELECT ROUTINE_NAME AS StoredProcedureName
FROM INFORMATION_SCHEMA.ROUTINES
WHERE ROUTINE_TYPE = 'PROCEDURE' --as opposed to a function
ORDER BY ROUTINE_NAME
2) Get the stored procedure create T-SQL:
select
c.text
from dbo.syscomments c
where c.id = object_id(N'StoredProcedureName')
order by c.number, c.colid
option(robust plan)
3) Run the create statement with NOEXEC on, so that the syntax is checked, but it doesn't actually try to create the stored procedure:
connection("SET NOEXEC ON", ExecuteNoRecords);
connection(StoredProcedureCreateSQL, ExecuteNoRecords);
connection("SET NOEXEC ON", ExecuteNoRecords);
Here is an amendment which deals with multiple schemas
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [dbo].[RefreshAllViews] AS
-- This sp will refresh all views in the catalog.
-- It enumerates all views, and runs sp_refreshview for each of them
DECLARE abc CURSOR FOR
SELECT TABLE_SCHEMA+'.'+TABLE_NAME AS ViewName
FROM INFORMATION_SCHEMA.VIEWS
OPEN abc
DECLARE #ViewName varchar(128)
-- Build select string
DECLARE #SQLString nvarchar(2048)
FETCH NEXT FROM abc
INTO #ViewName
WHILE ##FETCH_STATUS = 0
BEGIN
SET #SQLString = 'EXECUTE sp_RefreshView ['+#ViewName+']'
PRINT #SQLString
EXECUTE sp_ExecuteSQL #SQLString
FETCH NEXT FROM abc
INTO #ViewName
END
CLOSE abc
DEALLOCATE abc
GO