SQL Server - Return SCHEMA for sysobjects - sql

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

Related

In One DB I have 100+ tables, but I need staging table (start with STR_) wise column wise(Which is Status ) row count. in Dynamic query [duplicate]

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
'

SQL Server passing identifiers to stored procedures/dynamic SQL

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".

SQL query to find and replace text in a stored procedure

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.

How to copy and rename a VIEW/SP programmatically in SQL Server?

I know you can right-click on the selected VIEW/SP and select CREATE-TO, and you can just copy the generated script. But this has to be done via a SQL Client.
What I wish to do is that whenever there is an update on the VIEW/SP by my vendor, I would like to perform the backup of the affected VIEW/SP before running the ALTER VIEW/SP command from my vendor. I wish to do this using script rather than human interface so as to reduce the risk of human errors.
Can anyone help?
This should get you started.
DECLARE #SQL VARCHAR(MAX)
SET #SQL = ( SELECT Routine_Definition
FROM ( SELECT Routine_Catalog, Routine_Schema, Routine_Name, Routine_Definition
FROM INFORMATION_SCHEMA.ROUTINES
WHERE Routine_type = 'PROCEDURE'
UNION ALL
SELECT Table_Catalog, Table_Schema, Table_Name, View_Definition
FROM INFORMATION_SCHEMA.VIEWS
) def
WHERE Routine_Catalog = 'YourDatabase'
AND Routine_Schema = 'YourSchema'
AND Routine_Name = 'YourView/SP'
)
IF #SQL IS NULL
RETURN
EXEC SP_RENAME 'YourDatabase.YourSchema.YourView/SP', 'NewName', 'OBJECT'
EXEC (#sql)
Following is the link where you can find how to create/alter/delete Stored procedure using C# code
You can create front end form(GUI) in C# or your desired technology and in in this form
you vendor enter the detail of stored procedures.
http://msdn.microsoft.com/en-us/library/ms162190.aspx
Following are the scripts that you run in Database to find the detail of changes/Created stored procedures
SELECT name 'Alterd Procedures'
FROM sys.objects
WHERE type = 'P'
AND DATEDIFF(D,modify_date, GETDATE()) < 5
SELECT name 'Created Procedures'
FROM sys.objects
WHERE type = 'P'
AND DATEDIFF(D,create_date, GETDATE()) < 5
5 is the no of days, you can change this according to your need
you can change 'P' to 'V' for views

Find stored procedure by name

Is there any way I can find in SQL Server Management Studio stored procedure by name or by part of the name? (on active database context)
Thanks for help
You can use:
select *
from
sys.procedures
where
name like '%name_of_proc%'
if you need the code you can look in the syscomments table
select text
from
syscomments c
inner join sys.procedures p on p.object_id = c.object_id
where
p.name like '%name_of_proc%'
Edit Update:
you can can also use the ansi standard version
SELECT *
FROM
INFORMATION_SCHEMA.ROUTINES
WHERE
ROUTINE_NAME LIKE '%name_of_proc%'
Assuming you're in the Object Explorer Details (F7) showing the list of Stored Procedures, click the Filters button and enter the name (or partial name).
This will work for tables and views (among other things) as well, not just sprocs:
SELECT
'[' + s.name + '].[' + o.Name + ']',
o.type_desc
FROM
sys.objects o
JOIN sys.schemas s ON s.schema_id = o.schema_id
WHERE
o.name = 'CreateAllTheThings' -- if you are certain of the exact name
OR o.name LIKE '%CreateAllThe%' -- if you are not so certain
It also gives you the schema name which will be useful in any non-trivial database (e.g. one where you need a query to find a stored procedure by name).
When I have a Store Procedure name, and do not know which database it belongs to, I use the following -
Use [master]
GO
DECLARE #dbname VARCHAR(50)
DECLARE #statement NVARCHAR(max)
DECLARE db_cursor CURSOR
LOCAL FAST_FORWARD
FOR
--Status 48 (mirrored db)
SELECT name FROM MASTER.dbo.sysdatabases WHERE STATUS NOT LIKE 48 AND name NOT IN ('master','model','msdb','tempdb','distribution')
OPEN db_cursor
FETCH NEXT FROM db_cursor INTO #dbname
WHILE ##FETCH_STATUS = 0
BEGIN
SELECT #statement = 'SELECT * FROM ['+#dbname+'].INFORMATION_SCHEMA.ROUTINES WHERE [ROUTINE_NAME] LIKE ''%name_of_proc%'''+';'
print #statement
EXEC sp_executesql #statement
FETCH NEXT FROM db_cursor INTO #dbname
END
CLOSE db_cursor
DEALLOCATE db_cursor
You can use this query:
SELECT
ROUTINE_CATALOG AS DatabaseName ,
ROUTINE_SCHEMA AS SchemaName,
SPECIFIC_NAME AS SPName ,
ROUTINE_DEFINITION AS SPBody ,
CREATED AS CreatedDate,
LAST_ALTERED AS LastModificationDate
FROM INFORMATION_SCHEMA.ROUTINES
WHERE
(ROUTINE_DEFINITION LIKE '%%')
AND
(ROUTINE_TYPE='PROCEDURE')
AND
(SPECIFIC_NAME LIKE '%AssessmentToolDegreeDel')
As you can see, you can do search inside the body of Stored Procedure also.
For SQL Server version 9.0 (2005), you can use the code below:
select *
from
syscomments c
inner join sys.procedures p on p.object_id = c.id
where
p.name like '%usp_ConnectionsCount%';
Option 1: In SSMS go to View > Object Explorer Details or press F7. Use the Search box. Finally in the displayed list right click and select Synchronize to find the object in the Object Explorer tree.
Option 2: Install an Add-On like dbForge Search. Right click on the displayed list and select Find in Object Explorer.
Very neat trick I stumble upon trying some SQL injection, in object explorer in the search box just use your percentage characters, and this will search EVERYTHING stored procedures, functions, views, tables, schema, indexes...I tired of thinking of more :)
Search Pattern