How can I find and replace specific text in a stored procedure?
I have the find and replace query but I'm not sure how to post that back to the stored procedure or update the stored procedure with the query result.
Here is the query that I am using for the find and replace:
SELECT
REPLACE (object_definition(object_id('storedprocedure_1')), 'findstring', 'replacestring')
Declare #spnames CURSOR
Declare #spname nvarchar(max)
Declare #moddef nvarchar(max)
Set #spnames = CURSOR FOR
select distinct object_name(c.id)
from syscomments c, sysobjects o
where c.text like '%findtext%'
and c.id = o.id
and o.type = 'P'
OPEN #spnames
FETCH NEXT
FROM #spnames into #spname
WHILE ##FETCH_STATUS = 0
BEGIN
Set #moddef =
(SELECT
Replace ((REPLACE(definition,'findtext','replacetext')),'ALTER','create')
FROM sys.sql_modules a
JOIN
( select type, name,object_id
from sys.objects b
where type in (
'p' -- procedures
)
and is_ms_shipped = 0
)b
ON a.object_id=b.object_id where b.name = #spname)
exec('drop procedure dbo.' + #spname)
execute sp_executesql #moddef
FETCH NEXT FROM #spnames into #spname
END
This is what I was able to come up with, its currently doing the text replace and re creating the stored procedures.
You can get the definition of a stored procedure like so:
use <your database>
go
select
definition
from
sys.sql_modules
where
object_id = OBJECT_ID('<your schema.procedure_name>')
That will return the actual definition of the procedure you specify. You can build a list of stored procedures and walk through that one at a time, I guess. Not so sure I'd recommend trying to change them in sys.sql_modules, but at least you could find the ones that contain the text you're looking for.
Related
I am trying to write this query to find all tables with specific column with some specific value. This is what I've done so far -
EXEC sp_MSforeachtable
#command1='
IF EXISTS (SELECT * FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA=PARSENAME("?",2) AND TABLE_NAME=PARSENAME("?",1) AND COLUMN_NAME="EMP_CODE")
BEGIN
IF (SELECT COUNT(*) FROM ? WHERE EMP_CODE="HO081")>0
BEGIN
SELECT * FROM ? WHERE EMP_CODE="HO081"
END
END
'
I hope my intensions are clear, I just want to select only those tables where the column EMP_CODE is present and in those tables I want to select those rows where EMP_CODE='HO081'.
Edit -
Now it stands like this. But I'm not able to replace #EMPCODE variable in the query.
DECLARE #EMPCODE AS VARCHAR(20)
SET #EMPCODE='HO081'
EXEC sp_MSforeachtable
#command1='
DECLARE #COUNT AS INT
SELECT #COUNT=COUNT(*) FROM ? WHERE EMP_CODE='''+#EMPCODE+'''
IF #COUNT>0
BEGIN
PRINT PARSENAME("?",1)+'' => ''+CONVERT(VARCHAR,#COUNT)+'' ROW(S)''
--PRINT ''DELETE FROM ''+PARSENAME("?",1)+'' WHERE EMP_CODE='''''+#EMPCODE+'''''''
END
',#whereand='AND O.ID IN (SELECT OBJECT_ID FROM SYS.COLUMNS C WHERE C.NAME='''+#EMPCODE+''')'
You know how sp_MSforeachtable is undocumented, and may go away at any time/be modified?
Well, if you're happy to ignore that, it has another parameter called #whereand, which is appended to the WHERE clause of the internal query that is being used to find the tables (and should start with an AND).
You also have to know that there's an alias, o against sysobjects, and a second alias syso against sys.all_objects.
Using this knowledge, you might craft your #whereand parameter as:
EXEC sp_MSforeachtable
#command1='...',
#whereand='AND o.id in (select object_id from sys.columns c where c.name=''EMP_CODE'')'
You can now also simplify your command1, since you know it will only be run against tables containing an EMP_CODE column. I'd probably take out the COUNT(*) condition also, since I don't see what value it's adding.
Updated based on your further work, and tested against one table:
DECLARE #EMPCODE AS VARCHAR(20)
SET #EMPCODE='HO081'
declare #sql nvarchar(2000)
set #sql = '
DECLARE #COUNT AS INT
SELECT #COUNT=COUNT(*) FROM ? WHERE EMP_CODE='''+#EMPCODE+'''
IF #COUNT>0
BEGIN
PRINT PARSENAME("?",1)+'' => ''+CONVERT(VARCHAR,#COUNT)+'' ROW(S)''
--PRINT ''DELETE FROM ''+PARSENAME("?",1)+'' WHERE EMP_CODE='''''+#EMPCODE+'''''''
END
'
EXEC sp_MSforeachtable
#command1=#sql,#whereand='AND O.ID IN (SELECT OBJECT_ID FROM SYS.COLUMNS C WHERE C.NAME=''EMP_CODE'')'
(I've reverted the #whereand to query for EMP_CODE, since you don't want to replace the value there).
The issue is that, you can pass parameters to a stored procedure, or literals, but you can't perform calculations/combining actions between them - so I moved the construction of the sql statement out into a separate action.
I guess you get an error of some kind, perhaps Invalid column name 'EMP_CODE'?
It's because the code is compiled before you check for the column.
You could do like this instead.
EXEC sp_MSforeachtable
#command1='
IF EXISTS (SELECT * FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA=PARSENAME("?",2) AND TABLE_NAME=PARSENAME("?",1) AND COLUMN_NAME="EMP_CODE")
BEGIN
EXEC(''
IF (SELECT COUNT(*) FROM ? WHERE EMP_CODE="HO081")>0
BEGIN
SELECT * FROM ? WHERE EMP_CODE="HO081"
END
'')
END
'
I need to store the procedures acutal parameter values to a temp table.
I tried to create a script which can be applied for different stored procedures, therefore the script cannot contain the name of the parameters.
For formatting reasons I couldn't add the scipt. Let me explain in words.
I have a temp table with columns ParameterName and ParameterValue
I inserted the Parameternames using table sys.parameters
Within the SP I try to update temp table ParameterValue with parameter values which the SP was called.
I created dynamic SQL for each parameter one-by-one, I used #ParameterName variable to hold the parameter in row
However I cannot add the value of the parameter (the name of given parameter in #ParameterName) to dynamic SQL
Also tried SP_EXECUTESQL
Please help how to solve this one.
If you are using dynamic queries,instead of #temp table ,use ##temp table or permanent table. This may solve your issue.
This will give you all of your procedures, their parameters, and their parameter types. If you want it into a temp you can just remove the commented out portion. Also if you want just one procedure, then you can set #ProcName to the name of that procedure.
declare #ProcName varchar(4000) = null
select
o.name as ProcName,
p.name as ParamName,
t.name as ParamType
--into #someTemp
from
sys.objects o
inner join
sys.parameters p on p.object_id = o.object_id
inner join
sys.types t on t.system_type_id = p.system_type_id
where
o.type = 'P'
and #ProcName is null or o.name = #ProcName
UPDATE BASED ON YOUR COMMENTS
---------------------------------------------------------
--create a global temp
--Remember SQL will clean up (remove) your temp when it wants
---------------------------------------------------------
create table ##someTemp(
DT datetime,
ProcName varchar(256),
ParamName varchar(128),
ParamType varchar(128),
Val varchar(256))
go
---------------------------------------------------------
--create the procedure
---------------------------------------------------------
create procedure [dbo].[usp_test_param_insert] (#int char(1), #someString varchar(256))
as
insert into ##someTemp (DT,ProcName,ParamName, ParamType, val) values
(getdate(),'usp_test','#int','int',#int),
(getdate(),'usp_test','#someString','varchar(256)',#someString)
select #int, #someString
GO
---------------------------------------------------------
--call the proc a few times... i put the delay so you
--can see the time stamp changing
---------------------------------------------------------
exec usp_test_param_insert 1,'first string'
WAITFOR DELAY '00:00:05'
exec usp_test_param_insert 2,'second string'
WAITFOR DELAY '00:00:05'
exec usp_test_param_insert 3,'third string'
---------------------------------------------------------
--See your results
---------------------------------------------------------
select * from ##someTemp
Background:
SQL Server Management Studio allows to define own query shortcuts (Tools > Options > Environment > Keyboard > Query Shortcuts):
Image from: http://social.technet.microsoft.com/wiki/contents/articles/3178.how-to-create-query-shortcuts-in-sql-server-management-studio.aspx
my_schema.my_table
-- highlight it
-- press CTRL + 3 and you will get the number of rows in table
It works ok, but it concatenates query in basic form (as far as I know only at the end). Query:
SELECT COUNT(*) FROM my_schema.my_table;
Attempt #1
Now I want to write something more specific, for example pass/concatenate table name to following query (this is just example):
SELECT * FROM sys.columns WHERE [object_id] = OBJECT_ID(...)
So when I write in query shortcuts:
SELECT * FROM sys.columns WHERE [object_id] = OBJECT_ID('
I have to use:
my_schema.my_table')
-- highlight it
-- press CTRL + 3
The additional ') is very ugly and inconvenient.
Attempt #2:
The second trial is to use Dynamic-SQL:
EXEC dbo.sp_executesql
N'SELECT * FROM sys.columns WHERE [object_id] = OBJECT_ID(#obj_name)'
,N'#obj_name SYSNAME'
,
Executing:
my_table
-- highligt it
-- and run
LiveDemo
Works also when table name is quoted [my_table]. As long as object is in dbo(default) schema.
The problem is that when table has schema it won't work:
EXEC dbo.sp_executesql
N'SELECT * FROM sys.columns WHERE [object_id] = OBJECT_ID(#obj_name)'
,N'#obj_name SYSNAME'
,
Executing:
my_schema.my_table
[my_schema].[my_table]
LiveDemo2
Incorrect syntax near '.'.
Of course I could write:
EXEC dbo.sp_executesql
N'SELECT * FROM sys.columns WHERE [object_id] = OBJECT_ID(#obj_name)'
,N'#obj_name SYSNAME'
,'
and call it as:
[my_schema].[my_table]'
But additional ' is also ugly and inconvenient.
Questions:
Is it possible to pass value, to query shortcuts window, in the middle (positional or even more than one value)?
Is it possible to pass do stored_procedure/dynamic-sql qualified identifier without wraping it with ', "?
Remarks:
I do not search for plugins to SSMS
I do not want to wrap object_name as "my_schema.my_table"
I know there is sp_helptext (this is just example, I search for method)
First question is tool specific (I am aware of it), but second is about SQL Server.
EDIT:
To clarify passing identifier to SP without ' or ":
CREATE TABLE dbo.my_table(col INT);
GO
CREATE PROCEDURE dbo.my_proc
#a SYSNAME
AS
SELECT *
FROM sys.columns
WHERE [object_id] = OBJECT_ID(#a)
GO
EXEC dbo.my_proc
#a = my_table;
EXEC dbo.my_proc
#a = dbo.my_table;
-- Incorrect syntax near '.'.
LiveDemo3
1. Is it possible to pass value, to query shortcuts window, in the middle?
To my knowledge, there is no workaround to achieve this.
1-b. Is it possible to pass more than one value?
It can be done for string values using a separator character and then splitting the value on the other side. Sadly, there isn't many special character to fulfill this job because they pretty much all raise a syntax error. However '#' could be a wise choice because it's already a special character for SQL for temp table going in tempDB. Just check if you don't already have identifier that are using it because it's permitted by SQL (tough, it's forbidden as first char).
Here is an example of this :
Create a stored procedure to receive the arguments into one single string and split the string to have each arguments.
CREATE PROCEDURE sp_PassingMultipleStringValues
#Param1 NVARCHAR(MAX)
AS
--Here I'm using a XML split, but feel free to use any string split function you already have.
DECLARE #xml AS XML,
#separator AS VARCHAR(1)
SELECT #separator ='#',
#xml = CAST('<X>'+ (REPLACE(#Param1,#separator ,'</X><X>') +'</X>') AS XML)
SELECT N.value('.', 'VARCHAR(200)') AS value
FROM #xml.nodes('X') as T(N)
--Do whatever is needed with them
Then configure your shortcut as seem on this image. (Note the space at the end)
Result :
2. Is it possible to pass to a stored_procedure/dynamic-sql qualified identifier without wraping it with ', "?
Do you have multiple schema with the same identifier?
Because if not, what about retrieve it on the other side using sys.schemas instead of passing it?
Instead of having an inconvenient character to type at the end, you would have fewer things to type.
With the retrieved schema, you can then do dynamic SQL for whatever is needed with it.
SELECT #Param1 = REPLACE(REPLACE(#Param1, '[', ''), ']', '')
SELECT TOP 1 #Param1 = [Schema].name + '.' + #Param1
FROM sys.objects AS obj
JOIN sys.schemas AS [Schema] ON obj.schema_id = [Schema].schema_id
WHERE obj.name = #Param1
SELECT *
FROM sys.columns
WHERE [object_id] = OBJECT_ID(#Param1)
DECLARE #Query NVARCHAR(MAX) = 'SELECT TOP 1 * FROM ' + #Param1
EXEC sp_sqlexec #Query
If you do want to handle two different schema with the same identifier then it's still feasible by passing the schema and the identifier as two arguments using the method explained in answer 1-b.
Everything in one example
Since here we want to pass multiple identifiers and specify their schema, two separators are needed.
CREATE PROCEDURE sp_MultiArgsWithSchema
#Param1 NVARCHAR(MAX)
AS
SELECT #Param1 = REPLACE(REPLACE(#Param1, '[', ''), ']', '')
--Here I'm using a XML split, but feel free to use any string split function you already have.
DECLARE #xml AS XML,
#ArgSeparator AS VARCHAR(2),
#SchemaSeparor AS VARCHAR(1)
SELECT #ArgSeparator = '##',
#SchemaSeparor = '#',
#xml = CAST('<X>'+ (REPLACE(#Param1,#ArgSeparator, '</X><X>') +'</X>') AS XML)
IF OBJECT_ID('tempdb..#QualifiedIdentifiers') IS NOT NULL
DROP TABLE #QualifiedIdentifiers;
--While splitting, we are putting back the dot instead of '#' between schema and name of object
SELECT QualifiedIdentifier = REPLACE(N.value('.', 'VARCHAR(200)'), #SchemaSeparor, '.')
INTO #QualifiedIdentifiers
FROM #xml.nodes('X') as T(N)
SELECT * FROM #QualifiedIdentifiers
--From here, use what is inside #QualifiedIdentifiers and Dynamic SQL if need to achieve what is needed
DECLARE #QualifiedIdentifier NVARCHAR(500)
WHILE EXISTS(SELECT TOP 1 1 FROM #QualifiedIdentifiers)
BEGIN
SELECT TOP 1 #QualifiedIdentifier = QualifiedIdentifier
FROM #QualifiedIdentifiers
SELECT *
FROM sys.columns
WHERE [object_id] = OBJECT_ID(#QualifiedIdentifier)
DELETE TOP (1)
FROM #QualifiedIdentifiers
WHERE QualifiedIdentifier = #QualifiedIdentifier
END
Usage (note that specifying the schema isn't mandatory) :
So, since it is inconvenient to have to double the splitting character, it would be best if schema could be guessed like stated above.
Here is a long shot to pass multi-part identifier without wrapping it with quotes.
Solution:
The query shortcuts is going to create a synonym in the database with a specific name and a DDLTrigger to intercept this specific synonym creation.
Setup up the following shortcut in Query ShortCuts. (Make sure you include last space)
DECLARE #CreateTriggerSQL NVARCHAR(MAX) = 'CREATE TRIGGER DDLTrigger_QueryShortcutX ON DATABASE FOR CREATE_SYNONYM AS BEGIN DECLARE #EventData XML = EVENTDATA(), #SynonymName NVARCHAR(255), #DbName NVARCHAR(255), #SchemaName NVARCHAR(255), #ObjectName NVARCHAR(255), #Alias NVARCHAR(255) SELECT #SynonymName = #EventData.value(''(/EVENT_INSTANCE/ObjectName)[1]'', ''NVARCHAR(255)'') IF(#SynonymName = ''QueryShortcutX'') BEGIN DROP SYNONYM QueryShortcutX DROP TRIGGER DDLTrigger_QueryShortcutX ON DATABASE SELECT #DbName = #EventData.value(''(/EVENT_INSTANCE/DatabaseName)[1]'', ''NVARCHAR(255)''), #SchemaName = #EventData.value(''(/EVENT_INSTANCE/TargetSchemaName)[1]'', ''NVARCHAR(255)''), #ObjectName = #EventData.value(''(/EVENT_INSTANCE/TargetObjectName)[1]'', ''NVARCHAR(255)''), #Alias = (CASE WHEN LEN(#SchemaName) > 0 THEN #SchemaName + ''.'' ELSE '''' END) + #ObjectName /*EXEC yourStoredProcHere #Param = #Alias*/ SELECT DbName = #DbName, SchemaName = #SchemaName, ObjectName = #ObjectName, Alias = #Alias, ObjectId = OBJECT_ID(#Alias) END END' EXEC sp_executeSQL #CreateTriggerSQL CREATE SYNONYM QueryShortcutX FOR
As #Vladimir suggested, here we use "sp_executesql" to be able to create the trigger and the synonym at the same time.
Here is the code of the trigger without being inlined.
CREATE TRIGGER DDLTrigger_QueryShortcutX ON DATABASE FOR CREATE_SYNONYM
AS
BEGIN
DECLARE #EventData XML = EVENTDATA(),
#SynonymName NVARCHAR(255),
#DbName NVARCHAR(255),
#SchemaName NVARCHAR(255),
#ObjectName NVARCHAR(255),
#Alias NVARCHAR(255)
SELECT #SynonymName = #EventData.value('(/EVENT_INSTANCE/ObjectName)[1]', 'NVARCHAR(255)')
--Safety in case someone else really create a synonym meanwhile.
IF(#SynonymName = 'QueryShortcutX')
BEGIN
--2. Clean up what we created
DROP SYNONYM QueryShortcutX
DROP TRIGGER DDLTrigger_QueryShortcutX ON DATABASE
--3. Parsing identifier code here
SELECT #DbName = #EventData.value('(/EVENT_INSTANCE/DatabaseName)[1]', 'NVARCHAR(255)'),
#SchemaName = #EventData.value('(/EVENT_INSTANCE/TargetSchemaName)[1]', 'NVARCHAR(255)'),
#ObjectName = #EventData.value('(/EVENT_INSTANCE/TargetObjectName)[1]', 'NVARCHAR(255)'),
#Alias = (CASE WHEN LEN(#SchemaName) > 0 THEN #SchemaName + '.' ELSE '' END) + #ObjectName
--4. Here, write any print/select statement you want.
--For maintenance, it would be easier to just call a stored procedure from here with parameter and put the desired print/select there.
--Thus avoiding to redo inlining the whole trigger each time.
--EXEC yourStoredProcHere #Param = #Alias
SELECT DbName = #DbName,
SchemaName = #SchemaName,
ObjectName = #ObjectName,
Alias = #Alias,
ObjectId = OBJECT_ID(#Alias)
END
END
Here is the code of the shortcut without being inlined.
DECLARE #CreateTriggerSQL NVARCHAR(MAX) = 'Trigger creation code here...'
IF EXISTS(SELECT TOP 1 1 FROM sys.triggers WHERE name = 'DDLTrigger_QueryShortcutX')
BEGIN
DROP TRIGGER DDLTrigger_QueryShortcutX ON DATABASE
END
EXEC sp_executeSQL #CreateTriggerSQL
IF EXISTS(SELECT TOP 1 1 FROM sys.synonyms WHERE name = 'QueryShortcutX')
BEGIN
DROP SYNONYM QueryShortcutX
END
CREATE SYNONYM QueryShortcutX FOR
The trigger drop itself and the synonym to avoid schema pollution.
The trigger parse the information to retrieve identifier.
Use the identifier for your needs. (use dynamic SQL if needed)
Results for each test item
1.RealColumnName
2.WhatEverText
3.dbo.tests
4.[No selection]
5.dbo.tests.very.much
DbName SchemaName ObjectName Alias ObjectId
1.TEST RealColumnName RealColumnName NULL --FN OBJECT_ID doesn't return value with only column name
2.TEST WhatEverText WhatEverText NULL
3.TEST dbo tests dbo.tests 245575913
4.Incorrect syntax near 'FOR'.
5.TEST very much very.much NULL
The parsing I've made doesn't handle identifier with more than two multipart properly. If you want to improve it. The following XML show you which tag to use.
<TargetServerName>dbo</TargetServerName>
<TargetDatabaseName>tests</TargetDatabaseName>
<TargetSchemaName>very</TargetSchemaName>
<TargetObjectName>much</TargetObjectName>
Note:
If you prefer, you can let the trigger stay permanently within the database.
Also, if you want to pass multiple identifiers, string parsing like I do in my other answer is still a possibility here.
To use this solution, user will have to have "create synonym permission" and either own the schema or have "ALTER SCHEMA permission".
How to I get the SCHEMA when doing a select on sysobjects?
I am modifing a stored procedure called SearchObjectsForText which returns only the Name but I would also like to include the SCHEMA.
Right now it is doing something similar to this:
SELECT DISTINCT name
FROM sysobjects
I would like to know what tables need to be joined to return the SCHEME for each 'name'.
If you mean SQL Server 2005 or higher, use sys.objects instead of sysobjects:
SELECT sys.objects.name, sys.schemas.name AS schema_name
FROM sys.objects
INNER JOIN sys.schemas ON sys.objects.schema_id = sys.schemas.schema_id
2005 introduced schemas. up to 2000, users equaled schemas. The same query for SQL Server 2000:
SELECT sysusers.name AS OwnerName, sysobjects.name
FROM sysobjects
INNER JOIN sysusers ON sysobjects.uid = sysusers.uid
On Sql Server 2005 (and above) you can use the sys.objects view:
select
name as ObjectName,
schema_Name(schema_id) as SchemaName
from
sys.objects
In Sql Server 2000 (and below), "schema" had a different conceptual meaning. Note from MSDN:
In earlier releases of SQL Server, databases could contain an entity called a "schema", but that entity was effectively a database user. SQL Server 2005 is the first release of SQL Server in which a schema is both a container and a namespace.
Could you use the Information_Schema view(s) instead?
SELECT DISTINCT table_name, table_schema
FROM INFORMATION_SCHEMA.TABLES
According to the MSDN page (for SQL Server 2008 and above),
Do not use INFORMATION_SCHEMA views to determine the schema of an object. The only reliable way to find the schema of a object is to query the sys.objects catalog view.
However, it seems that they're probably referring to an issue where you have a table name and are trying to find its schema, which wouldn't work if there were multiple tables with the same name (in different schemas). If you're querying for multiple results (not just trying to find the schema for a specific table), then it should be fine.
I would favor using the more focused "sys" views - sys.procedures instead of sys.objects. You'll need to join it with the sys.schemas view to get schema name and such.
select
p.name,
s.name 'Schema',
p.type_desc, p.create_date, p.modify_date
from
sys.procedures p
inner join
sys.schemas s ON p.schema_id = s.schema_id
I would start to get away from using "sysobjects" since Microsoft clearly states in Books Online that "sysobjects" is subject to removal in a future release:
This SQL Server 2000 system table is included as a view for backward compatibility. We recommend that you use the current SQL Server system views instead. To find the equivalent system view or views, see Mapping SQL Server 2000 System Tables to SQL Server 2005 System Views. This feature will be removed in a future version of Microsoft SQL Server. Avoid using this feature in new development work, and plan to modify applications that currently use this feature.
Marc
Just to repeat what's already been suggested here, here's what I've used, to get a list of Tables, Stored Procedures, Views and Functions in my database:
SELECT schema_Name(schema_id) as SchemaName,
[name], -- Name of the Table, Stored Procedure or Function
[type] -- 'V' for Views, 'U' for Table, 'P' for Stored Procedure, 'FN' for function
FROM sys.objects
WHERE [type_desc] IN ( 'USER_TABLE', 'SQL_STORED_PROCEDURE', 'VIEW', 'SQL_SCALAR_FUNCTION')
AND [name] NOT LIKE 'sp_%'
AND [name] NOT LIKE 'fn_%'
ORDER BY 3 DESC, -- type first
1 ASC, -- then schema
2 ASC -- then function/table name
...and here's what our good friend Northwind would return...
In SQL 200:
select DISTINCT
name as ObjectName,
USER_NAME(uid) as SchemaName
from
sysobjects
In earlier releases of SQL Server, databases could contain an entity called a "schema", but that entity was effectively a database user.
Have included an option to delete all objects starting with certain prefix and optionally from certain schema.
By the way, I added extra query to get all types which are not stored on sysobjects by default.
I have uploaded entire sample script to GitHub:
DropAll_Dnn_Objects.sql
Part 1: Temporary Stored Procedure:
IF OBJECT_ID('_temp_DropAllDnnObjects') IS NOT NULL
DROP PROCEDURE _temp_DropAllDnnObjects;
GO
CREATE PROCEDURE _temp_DropAllDnnObjects
#object_prefix NVARCHAR(30),
#schema_name sysname = NULL
AS
BEGIN
DECLARE #sname sysname, #name sysname, #type NVARCHAR(30)
DECLARE #object_type NVARCHAR(255), #sql NVARCHAR(2000), #count INT = 0
DECLARE curs CURSOR FOR
SELECT sname, [name], xtype
FROM (
SELECT SCHEMA_NAME(schema_id) as sname, [name], [type] as xtype
FROM sys.objects
WHERE [type] IN ('U', 'P', 'FN', 'IF', 'TF', 'V', 'TR')
AND name LIKE #object_prefix + '%'
AND (#schema_name IS NULL OR schema_id = SCHEMA_ID(#schema_name))
UNION ALL
SELECT SCHEMA_NAME(schema_id) as sname, [name], 'TYPE' as xtype
FROM sys.types
WHERE is_user_defined = 1
AND [name] LIKE #object_prefix + '%'
AND (#schema_name IS NULL OR schema_id = SCHEMA_ID(#schema_name))
) a
ORDER BY CASE xtype
WHEN 'P' THEN 1
WHEN 'FN' THEN 2
WHEN 'IF' THEN 3
WHEN 'TF' THEN 4
WHEN 'TR' THEN 5
WHEN 'V' THEN 6
WHEN 'U' THEN 7
WHEN 'TYPE' THEN 8
ELSE 9
END, name
OPEN curs;
FETCH NEXT FROM curs INTO #sname, #name, #type;
WHILE ##FETCH_STATUS = 0
BEGIN
SET #count = #count + 1
-- Configuration point 2
SET #object_type = CASE #type
WHEN 'P' THEN 'PROCEDURE'
WHEN 'FN' THEN 'FUNCTION'
WHEN 'IF' THEN 'FUNCTION'
WHEN 'TF' THEN 'FUNCTION'
WHEN 'TR' THEN 'TRIGGER'
WHEN 'V' THEN 'VIEW'
WHEN 'U' THEN 'TABLE'
WHEN 'TYPE' THEN 'TYPE'
END
SET #sql = REPLACE(REPLACE(REPLACE('DROP <TYPE> [<SCHEMA>].[<NAME>];',
'<TYPE>', #object_type),
'<SCHEMA>', #sname),
'<NAME>', #name)
BEGIN TRY
PRINT #sql
EXEC(#sql)
END TRY
BEGIN CATCH
PRINT 'ERROR: ' + ERROR_MESSAGE()
END CATCH
FETCH NEXT FROM curs INTO #sname, #name, #type;
END;
PRINT CONCAT('Objects Found: ', #Count)
PRINT ''
PRINT '------------------------------------------------------'
PRINT ''
CLOSE curs;
DEALLOCATE curs;
RETURN #Count
END;
GO
It will continue on errors (and display the error message). It will return a count of all objects found.
Part 2: Call Stored Procedure with parameters:
You can create a WHILE loop in order to run the command until no object is left (dependencies), as follows:
DECLARE #count INT = 1
WHILE #count > 0 EXEC #count = _temp_DropAllDnnObjects 'dnn';
SET #count = 1
WHILE #count > 0 EXEC #count = _temp_DropAllDnnObjects 'aspnet';
SET #count = 1
WHILE #count > 0 EXEC #count = _temp_DropAllDnnObjects 'vw_aspnet';
GO
Part 3: Finally, get rid of the procedure:
IF OBJECT_ID('_temp_DropAllDnnObjects') IS NOT NULL
DROP PROCEDURE _temp_DropAllDnnObjects;
GO
Instead of a view, why not use this to populate a temporary table you can use?
This is the solution I use in stored procedures
This is the best way to get a schema dynamically and add it to the different tables within a database in order to get other information dynamically
select #sql = 'insert #tables SELECT ''[''+SCHEMA_NAME(schema_id)+''.''+name+'']'' AS SchemaTable FROM sys.tables'
exec (#sql)
of course #tables is a dynamic table in the stored procedure
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.