MSSQL: How do you script Stored Procedure creation with code? - sql

I am trying to query for a list of stored procedure definitions using information_schema.routines that exist in one database but not in another.
SELECT
t1.Routine_Definition
FROM
[server1].MyDatabase.INFORMATION_SCHEMA.Routines t1
LEFT JOIN
[server2].MyDatabase.INFORMATION_SCHEMA.Routines t2 ON t1.Routine_Name = t2.Routine_Name
WHERE
t2.Routine_Name is null
This gives me the query definitions in a single line so when I have a comment like this
--Some comment
SELECT Column
FROM Somewhere
The SQL gets commented out and I cannot use the definition to create the SP.
How to I parse this back with the proper line breaks?
or
Is there a better way to get these scripts (using code)?

The stored procedure is only displayed on one line in Management Studio. If you run the query with results to text, or use the following, you will get the correct line breaks:
declare #sql varchar(8000) -- varchar(max) in SQL 2005+
SELECT
#sql = t1.Routine_Definition
FROM
INFORMATION_SCHEMA.Routines t1
print #sql

DECLARE MY_CURSOR Cursor
FOR
SELECT
t1.Routine_Definition
FROM
[server1].MyDatabase.INFORMATION_SCHEMA.Routines t1
LEFT JOIN
[server2].MyDatabase.INFORMATION_SCHEMA.Routines t2 ON t1.Routine_Name = t2.Routine_Name
WHERE
t2.Routine_Name is null AND
LEN(t1.Routine_Definition) < 4000
Open My_Cursor
DECLARE #sql VARCHAR(MAX)
FETCH NEXT FROM MY_Cursor INTO #sql
While (##FETCH_STATUS <> -1)
BEGIN
IF (##FETCH_STATUS <> -2)
Print #sql
FETCH NEXT FROM MY_CURSOR INTO #sql
END
CLOSE MY_CURSOR
DEALLOCATE MY_CURSOR
GO
Here is how I implemented ck's solution...
the INFORMATION_SCHEMA view only returns the first 4000 characters in the definition. (Ideally you wont have SP that are that long)You will want to script those manually or some other way.

I think the easiest way of getting your stored procedures is to use the Import/Export utility that is built into SQL Server Management Studio. From there you can export your Stored Procedure Objects into the code window or to a file that you can immediately run.

Related

Execute dynamic select query stored in a table

I have stored select statements in a table column named RuleSql. In the future the table size will go large, so how can I execute all the stored select statements at the same time to get the result?
I have used:
EXEC sp_executesql
But it is not helpful for me.
It's very poor practice storing SQL code in a table. Have you looked at views, stored procedures or inline table-valued functions?
Anyway, to execute the stored SQL in a table you would do something like this....
DECLARE #Sql NVARCHAR(MAX);
SELECT TOP 1 #Sql = RuleSql
FROM TableName --<-- table where sql is stored
WHERE <Some Condition>
Exec sp_executesql #Sql
Just saw your edit. To execute all the queries at once you would use a cursor something like.....
DECLARE #Sql NVARCHAR(MAX);
DECLARE Cur CURSOR LOCAL FAST_FORWARD FOR
SELECT RuleSql
FROM TableName --<-- table where sql is stored
OPEN Cur
FETCH NEXT FROM Cur INTO #Sql
WHILE (##FETCH_STATUS = 0)
BEGIN
Exec sp_executesql #Sql
FETCH NEXT FROM Cur INTO #Sql
END
CLOSE Cur
DEALLOCATE Cur;
If you want this same information but for the whole database (all tables of a database) and create a table wit results you can use followin

Use SELECT results as a variable in a loop

I've searched here and elsewhere, and haven't found an answer yet. Hope I didn't miss it.
Using SQL Server Management Studio 2008 R2.
I have n specific databases on my server (there are other DBs as well, but I'm only interested in some of them)
Each of these databases has a table within it, which all have the same name. The only difference is the DB name. I want to aggregate these tables together to make one big table on a different database (different to the other DBs).
I can get the db names from the results of a query.
N is unknown.
Is a loop the way to go about this?
I was thinking something along the lines of the following pseudocode:
Set #dbnames = SELECT DISTINCT dbname FROM MyServer.dbo.MyTable
For each #name in #dbnames
INSERT INTO ADifferentDB.dbo.MyOtherTable
SELECT * FROM #name.dbo.table
Next name
(Clearly I'm new to using SQL variable as well, as you can see)
Your first problem is about iterating the databases: you cand do that with a cursor
Then you have another problem, executing a query where part of it is variable (database's name). You can do that with execute function.
All that is something similar to this:
DECLARE #query VARCHAR(max)
DECLARE #dbname VARCHAR(100)
DECLARE my_db_cursor CURSOR
FOR SELECT DISTINCT dbname FROM MyServer.dbo.MyTable
OPEN my_db_cursor
FETCH NEXT FROM my_db_cursor
INTO #dbname
WHILE ##FETCH_STATUS = 0
BEGIN
SET #query = 'INSERT INTO ADifferentDB.dbo.MyOtherTable
SELECT * FROM ' + #dbname + '.dbo.table'
EXECUTE(#query)
FETCH NEXT FROM my_db_cursor
INTO #dbname
END
CLOSE my_db_cursor
DEALLOCATE my_db_cursor
what you want to do is define a CURSOR for row-level operation. here is some doc
I would suggest using sp_MSForEachDB:
EXEC sp_MSForEachDB '
-- Include only the databases you care about.
IF NOT EXISTS (
SELECT *
FROM MySever.dbo.MyTable
WHERE dbname = ''?''
)
-- Exit if the database is not in your table.
RETURN
-- Otherwise, perform your insert.
INSERT INTO ADifferentDB.dbo.MyOtherTable
SELECT * FROM ?.dbo.table
'
In this case, ? is a token that is replaced with each database on the server.

Is there a better way to execute dynamic SQL that doesn't use a cursor?

I have dynamic SQL stored in a SQL table that I have to execute under certain conditions. Currently, we use cursors to handle that for us, but I was always told to avoid cursors when possible as they aren't the most efficient way of doing things. So, my question is: how do I execute dynamic SQL without them (if there's a way)? The entire system is built around this dynamic SQL mess, so there is no changing it.
For this, just assume the table has Id AS IDENTITY and SQL AS VARCHAR fields, where the SQL field contains the SQL to be executed (obviously).
EDIT:
Basically, I want to loop through the table and execute the SQL in the SQL column.
So, a row in the table will basically look like this:
ID SQL
-- ----------------------
1 SELECT * FROM RECORD
2 SELECT * FROM PERSON
3 SELECT * FROM LOCATION
I haven't written any code because what I'd write is a cursor to traverse through the table and execute it. I just don't know of any other ways of looping a table and executing that string as a SQL query other than something like:
DECLARE #sql VARCHAR(MAX)
DECLARE _cursor CURSOR
FOR
SELECT [SQL]
FROM #tmp2
OPEN _cursor
FETCH NEXT FROM _cursor INTO #sql
WHILE ##FETCH_STATUS = 0
BEGIN
PRINT ( #sql )
END
CLOSE _cursor
DEALLOCATE _cursor
You can use any number of concatenation tricks to make one big batch without using a cursor, I personally use the FOR XML trick a lot.
Here's an overview:
http://www.simple-talk.com/sql/t-sql-programming/concatenating-row-values-in-transact-sql/
However, the cursor (while generally a code smell) isn't going to contribute a terrible amount to the non-performance of this. And you will have an opportunity to handle errors etc a lot easier than with a single batch.
In addition, if you have DDL in some of those statements which has to be the first statement in a batch, then you would need to submit them in separate batches. EXEC or sp_executesql doesn't implement any batch splitting like SSMS has the GO batch separator.
Ignoring the fundamental flaws in this whole schema....
declare #sql nvarchar(max)
select #sql = ''
select #sql = #sql + SQL + ';' from #tmp2
exec sp_executesql #sql
At least we've got rid of your cursor now :)
EDIT: Code that is working for me...
create table #tmp2 (sql nvarchar(100))
insert #tmp2 values ('select * from sysobjects')
insert #tmp2 values ('Select * from sysColumns')
declare #sql nvarchar(max)
select #sql = ''
select #sql = #sql + SQL + ';' from #tmp2
exec sp_executesql #sql
drop table #tmp2

execute stored procedures returned from database table

I am working with sql server 2008
I have a database table that has a column containing a stored procedure name.
I want to query the database table which returns a list of the stored procedure names, and execute them.
The stored procedures are similar all having a select statment. The data returned in this select statement I want to insert in to a data base table.
Pseudo code looks like this:
INSERT INTO MyTable
EXECUTE sp_executesql SELECT StoredProcedureName FROM Table
Anyone able to assist me with correct sql for achieveing the above?
sp_executesql accepts a unicode string not a tsql statement. So you would need to execute your procedure(s) like this:
execute sp_executesql 'execute ' + #storedprocedurename
which will execute a single procedure.
You will need to write some iterative process to populate the #storedprocedurename variable from your source table.
This is pretty much same as #Coltech answer just with cursor.
DECLARE #spname VARCHAR(200)
DECLARE #sql VARCHAR(1000)
DECLARE your_cursor CURSOR FOR
SELECT spname
FROM yourTable;
OPEN your_cursor;
FETCH NEXT FROM your_cursor
INTO #spname;
WHILE ##FETCH_STATUS = 0
BEGIN
SET #sql = 'EXEC ' + #spname
execute sp_executesql #sql
FETCH NEXT FROM your_cursor
INTO #spname;
END
CLOSE your_cursor;

DROP SQL Tables if created date is more than a week - MS SQL Server

I want to create a Stored procedure and Job in Ms SQL server that would delete all tables in a schema that are more than a weeks old.
i create backups every single day and i want to automate the process by scheduling a job to delete any backups(SQL Tables) that are older than a week.
Your help would be greatly appreciated.
You can use the sys.objects keyword within SQL Server to accomplish this.
The query would be something like:
USE [Your_Database_Name];
GO
SELECT name AS object_name
,SCHEMA_NAME(schema_id) AS schema_name
,type_desc
,create_date
,modify_date
FROM sys.objects
WHERE create_date > GETDATE() - [No_Of_Days_Old]
ORDER BY create_date;
GO
This above example is a slight variation on the first example shown on the MSDN page that details the sys.objects keyword (A. Returning all the objects that have been modified in the last N days).
That page can be found here:
sys.objects (Transact-SQL)
and is a great resource for many different methods of querying the "metadata" of your database objects.
Of course, the above will simply "SELECT" the table name that will need to be deleted and won't actually delete (or DROP) the table from your database.
To achieve this, you will need a mechanism to issue a DROP TABLE command. Unfortunately, the DROP TABLE command won't accept a parameter valued table name (i.e. You can't do DROP TABLE #tablename), but you can build a string/varchar of a complete T-SQL statement and EXECUTE it).
To achieve this, you can use a CURSOR to loop through the results of the earlier SELECT statement, building a new T-SQL command in a string/varchar that will drop the table name. An example of this is below:
DECLARE #tname VARCHAR(100)
DECLARE #sql VARCHAR(max)
DECLARE db_cursor CURSOR FOR
SELECT name AS tname
FROM sys.objects
WHERE create_date > GETDATE() - 7
OPEN db_cursor
FETCH NEXT FROM db_cursor INTO #tname
WHILE ##FETCH_STATUS = 0
BEGIN
SET #sql = 'DROP TABLE ' + #tname
--EXEC (#sql)
PRINT #sql
FETCH NEXT FROM db_cursor INTO #tname
END
CLOSE db_cursor
DEALLOCATE db_cursor
Note that in the above example, I have commented out the line EXEC (#sql). This is the line that actually executes the T-SQL statement in the #sql variable, and since it's a destructive command, I simply commented it out and used a PRINT #sql command instead (the line below). Run this as is, to see what tables you're likely to delete, and when you're happy, uncomment the EXEC (#sql) command and comment out the PRINT #sql command!
You can use this query to get the list of tables that are more than a week old:
SELECT
[name]
,create_date
FROM
sys.tables
WHERE DATEDIFF(day, create_date, getdate()) > 7
So in your SP, you could then write an SP to loop over the tables returned from that query and delete them. You'll have to take into account that if the tables have foreign keys, the order in which you delete them is important, so this idea will probably need some tweeking if that's your scenario.