Rename SQL Server Schema - sql

How can I rename a schema using SQL Server?

If you have a large number of objects in a schema, you can use something like this to generate all the changes automatically (it only does tables and views, so before you run it, you might need to expand it to SPs, UDFs, etc.)
USE SandBox
DECLARE #OldSchema AS varchar(255)
DECLARE #NewSchema AS varchar(255)
DECLARE #newLine AS varchar(2) = CHAR(13) + CHAR(10)
SET #OldSchema = 'dbo'
SET #NewSchema = 'StackOverflow'
DECLARE #sql AS varchar(MAX)
SET #sql = 'CREATE SCHEMA [' + #NewSchema + ']' + #newLine
SELECT #sql = #sql + 'GO' + #newLine
SELECT #sql = #sql + 'ALTER SCHEMA [' + #NewSchema + '] TRANSFER [' + TABLE_SCHEMA + '].[' + TABLE_NAME + ']'
+ #newLine
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_SCHEMA = #OldSchema
SET #sql = #sql + 'DROP SCHEMA [' + #OldSchema + ']'
PRINT #sql -- NOTE PRINT HAS AN 8000 byte limit - 8000 varchar/4000 nvarchar - see comments
IF (0=1) EXEC (#sql)

You move individual objects from one schema to another via:
ALTER SCHEMA NewSchema TRANSFER OldSchema.Object;

I have combined both codes above and used cursors to not be limited by the size of the string variables, executing the commands individually. I assume you have already created the new schema and will drop the old one after certifying all is ok. It's safer... :)
DECLARE #OldSchema AS varchar(255)
DECLARE #NewSchema AS varchar(255)
SET #OldSchema = 'dbo'
SET #NewSchema = 'StackOverflow'
DECLARE #sql AS varchar(MAX)
DECLARE #Schema AS varchar(MAX)
DECLARE #Obj AS varchar(MAX)
-- First transfer Tables and Views
DECLARE CU_OBJS CURSOR FOR
SELECT TABLE_SCHEMA, TABLE_NAME
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_SCHEMA = #OldSchema
OPEN CU_OBJS
FETCH NEXT FROM CU_OBJS
INTO #Schema, #Obj
WHILE ##FETCH_STATUS = 0
BEGIN
SELECT #sql = 'ALTER SCHEMA [' + #NewSchema + '] TRANSFER [' + #OldSchema + '].[' + #Obj + ']'
PRINT #sql
-- EXEC (#sql)
FETCH NEXT FROM CU_OBJS
INTO #Schema, #Obj
END
CLOSE CU_OBJS
DEALLOCATE CU_OBJS
-- Now transfer Stored Procedures
DECLARE CU_OBJS CURSOR FOR
SELECT sys.schemas.name, sys.procedures.name
FROM sys.procedures,sys.schemas
WHERE sys.procedures.schema_id=sys.schemas.schema_id and sys.schemas.name = #OldSchema
OPEN CU_OBJS
FETCH NEXT FROM CU_OBJS
INTO #Schema, #Obj
WHILE ##FETCH_STATUS = 0
BEGIN
SELECT #sql = 'ALTER SCHEMA [' + #NewSchema + '] TRANSFER [' + #Schema + '].[' + #Obj + ']'
PRINT #sql
-- EXEC (#sql)
FETCH NEXT FROM CU_OBJS
INTO #Schema, #Obj
END
CLOSE CU_OBJS
DEALLOCATE CU_OBJS

The stored procedure to rename the schema which has more tables in SQL server 2008
IF OBJECT_ID ( 'dbo.RenameSchema', 'P' ) IS NOT NULL
DROP PROCEDURE dbo.RenameSchema;
GO
CREATE PROCEDURE dbo.RenameSchema
#OLDNAME varchar(500),
#NEWNAME varchar(500)
AS
/*check for oldschema exist or not */
IF NOT EXISTS (SELECT 1 FROM sys.schemas WHERE name = #OLDNAME)
BEGIN
RETURN
END
/* Create the schema with new name */
IF NOT EXISTS (SELECT 1 FROM sys.schemas WHERE name = #NEWNAME)
BEGIN
EXECUTE( 'CREATE SCHEMA ' + #NEWNAME );
END
/* get the object under the old schema and transfer those objects to new schema */
DECLARE Schema_Cursor CURSOR FOR
SELECT ' ALTER SCHEMA ' + #NEWNAME + ' TRANSFER '+ SCHEMA_NAME(SCHEMA_ID)+'.'+ name
as ALTSQL from sys.objects WHERE type IN ('U','V','P','Fn') AND
SCHEMA_NAME(SCHEMA_ID) = #OLDNAME;
OPEN Schema_Cursor;
DECLARE #SQL varchar(500)
FETCH NEXT FROM Schema_Cursor INTO #SQL;
WHILE ##FETCH_STATUS = 0
BEGIN
exec (#SQL)
FETCH NEXT FROM Schema_Cursor INTO #SQL;
END;
CLOSE Schema_Cursor;
DEALLOCATE Schema_Cursor;
/* drop the old schema which should be the user schema */
IF #OLDNAME <> 'dbo' and #OLDNAME <> 'guest'
BEGIN
EXECUTE ('DROP SCHEMA ' + #OLDNAME)
END
GO
Execute the procedure to rename the schema:
examples:
EXECUTE RenameSchema 'oldname','newname'
EXECUTE RenameSchema 'dbo','guest'

This is a short version but works well.
declare #sql varchar(8000), #table varchar(1000), #oldschema varchar(1000), #newschema varchar(1000)
set #oldschema = 'old'
set #newschema = 'dbo'
while exists(select * from sys.tables where schema_name(schema_id) = #oldschema)
begin
select #table = name from sys.tables
where object_id in(select min(object_id) from sys.tables where schema_name(schema_id) = #oldschema)
set #sql = 'alter schema [' + #newschema + '] transfer [' + #oldschema + '].[' + #table + ']'
exec(#sql)
end

For Procedures
USE DatabaseName
DECLARE #OldSchema AS varchar(255)
DECLARE #NewSchema AS varchar(255)
SET #OldSchema = 'ComputerLearn'
SET #NewSchema = 'Basic'
DECLARE #sql AS varchar(MAX)
SET #sql = 'CREATE SCHEMA [' + #NewSchema + ']' + CHAR(13) + CHAR(10)
SELECT #sql = #sql + 'ALTER SCHEMA [' + #NewSchema + '] TRANSFER [' + sys.schemas.name + '].[' + sys.procedures.name + ']'
+ CHAR(13) + CHAR(10)
FROM sys.procedures,sys.schemas
WHERE sys.procedures.schema_id=sys.schemas.schema_id and sys.schemas.name = #OldSchema
SET #sql = #sql + 'DROP SCHEMA [' + #OldSchema + ']'
PRINT #sql
IF (0=1) EXEC (#sql)

Easiest solution that worked for me is:
I have just one schema dbo with two tables PopulationByCountrySTG and CountryRegionSTG
(1) I created a new schema by executing,
create schema stg
(2) I executed the following commands,
ALTER SCHEMA stg TRANSFER dbo.PopulationByCountrySTG;
ALTER SCHEMA stg TRANSFER dbo.CountryRegionSTG;
All done. Let me know if it works for you.. Thanks Guys.

Related

Incorrect syntax SQL

Why do I get this error when I try to execute the following code?
I have a table NewTable1 with two columns: column1 and column2.
I get this error: Incorrect syntax near 'column2'.
--DROP COLUMN PROCEDURE
CREATE PROCEDURE DropColumn
#tableName varchar(50),
#columnName varchar(50)
AS
BEGIN
DECLARE #SQL nvarchar(500);
SET #SQL = N'ALTER TABLE ' + QUOTENAME(#tableName)
+ ' DROP COLUMN ' + QUOTENAME(#columnName);
EXEC sp_executesql #SQL;
END
RETURN 0
GO
USE SKI_SHOP;
EXEC DropColumn 'NewTable1', 'column2';
GO
Use appropriate data types. Also You will only be able to drop Columns for tables in callers default schema. Since procedure doesn't take schema into consideration, therefore you can only pass the table name and if a table exists in other than caller default schema they wont be able to delete it using this procedure .
CREATE PROCEDURE DropColumn
#tableName SYSNAME,
#columnName SYSNAME
AS
BEGIN
SET NOCOUNT ON;
DECLARE #SQL NVARCHAR(MAX);
SET #SQL = N' ALTER TABLE ' + QUOTENAME(#tableName)
+ N' DROP COLUMN ' + QUOTENAME(#columnName);
EXEC sp_executesql #SQL;
END
GO
I over looked some basic simple issues in my first approach, whenever creating of Dropping objects in SQL Server always check if they exist, to avoid any errors . A more complete and safe approach would be something like ...
This time I have also added schema as a parameter.
ALTER PROCEDURE DropColumn
#tableName SYSNAME,
#columnName SYSNAME,
#Schema SYSNAME,
#Success BIT OUTPUT
AS
BEGIN
SET NOCOUNT ON;
DECLARE #SQL NVARCHAR(MAX);
SET #SQL = N' IF EXISTS (SELECT * FROM sys.tables t
INNER JOIN sys.columns c
ON t.[object_id] = c.[object_id]
INNER JOIN sys.schemas sc
ON t.[schema_id] = sc.[schema_id]
WHERE t.name = #tableName
AND c.name = #columnName
AND sc.name = #Schema)
BEGIN
ALTER TABLE ' + QUOTENAME(#Schema)+ '.' + QUOTENAME(#tableName)
+ N' DROP COLUMN ' + QUOTENAME(#columnName)
+ N' SET #Success = 1; '
+ N' END
ELSE
BEGIN
SET #Success = 0;
END '
EXEC sp_executesql #SQL
,N'#tableName SYSNAME, #columnName SYSNAME, #Schema SYSNAME, #Success BIT OUTPUT'
,#tableName
,#columnName
,#Schema
,#Success OUTPUT
END
GO

Best Way To Convert All "SMALLINT" Columns Within A Database Schema To "BIT"? (SQL)

How do I convert all smallint type columns from my database to bit types?
I am using SQL Server 2008.
In SQL Server you can do it with ALTER TABLE my_table ALTER COLUMN my_column [new_datatype].
Be careful of things like default values because I haven't tested with them.
Example 1 - will give a list of queries for you to review / amend / execute (safer option).
DECLARE #TableSchema VARCHAR(100)
DECLARE #TableName VARCHAR(100)
DECLARE #ColumnName VARCHAR(100)
DECLARE #Query NVARCHAR(1000)
DECLARE #FromDataType NVARCHAR(50)
DECLARE #ToDataType NVARCHAR(50)
SET #TableSchema = 'dbo';
SET #FromDataType = 'smallint';
SET #ToDataType = 'bit';
DECLARE c CURSOR FAST_FORWARD FOR
SELECT TABLE_NAME, COLUMN_NAME
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_SCHEMA = #TableSchema
AND TABLE_NAME <> 'sysdiagrams'
AND DATA_TYPE = #FromDataType
OPEN c;
FETCH NEXT FROM c INTO #TableName, #ColumnName;
WHILE ##FETCH_STATUS = 0
BEGIN
SET #Query = N'ALTER TABLE ' + #TableName + N' ALTER COLUMN ' + #ColumnName + N' ' + #ToDataType -- + CHAR(13) + N'GO'
PRINT #Query
EXEC sp_EXECUTESQL #Query
FETCH NEXT FROM c INTO #TableName, #ColumnName;
END
CLOSE c;
DEALLOCATE c;
Example 2 - will execute (recommend running example 1 first!)
DECLARE #TableSchema VARCHAR(100)
DECLARE #TableName VARCHAR(100)
DECLARE #ColumnName VARCHAR(100)
DECLARE #Query NVARCHAR(1000)
DECLARE #FromDataType NVARCHAR(50)
DECLARE #ToDataType NVARCHAR(50)
SET #TableSchema = 'dbo';
SET #FromDataType = 'smallint';
SET #ToDataType = 'bit';
DECLARE c CURSOR FAST_FORWARD FOR
SELECT TABLE_NAME, COLUMN_NAME
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_SCHEMA = #TableSchema
AND TABLE_NAME <> 'sysdiagrams'
AND DATA_TYPE = #FromDataType
OPEN c;
FETCH NEXT FROM c INTO #TableName, #ColumnName;
WHILE ##FETCH_STATUS = 0
BEGIN
SET #Query = N'ALTER TABLE ' + #TableName + N' ALTER COLUMN ' + #ColumnName + N' ' + #ToDataType + CHAR(13) + N' GO'
PRINT #Query
FETCH NEXT FROM c INTO #TableName, #ColumnName;
END
CLOSE c;
DEALLOCATE c;
Please be careful doing this and test it on a backup database first. The following query will create ALTER statements for each column in your database that have SMALLINT datatype to convert them to BIT.
select 'ALTER TABLE ' + QUOTENAME(o.Name) + ' ALTER COLUMN ' + QUOTENAME(c.Name) + ' BIT' as Command
from sys.objects o
inner join sys.columns c
on o.object_id = c.object_id
where system_type_id = 52
and o.Type = 'U'
Also, be sure each column listed only contains 1 or 0 or you will get truncation errors when you run the script.
If you are asking about converting the column data type, I don't thing you can do that directly. You can add a new column as BIT and populate it from the old column, then drop the old column and rename the new one back to the old name.
See the online docs for more info.

Object does not exist or is not a valid using 'sp_changeobjectowner'

I changed the table schema from dbo to db_owner using the SQL statement below (SQL 2008 R2):
DECLARE #old sysname, #new sysname, #sql varchar(1000)
SELECT
#old = 'db_owner'
, #new = 'dbo'
, #sql = '
IF EXISTS (SELECT NULL FROM INFORMATION_SCHEMA.TABLES
WHERE
QUOTENAME(TABLE_SCHEMA)+''.''+QUOTENAME(TABLE_NAME) = ''?''
AND TABLE_SCHEMA = ''' + #old + '''
)
EXECUTE sp_changeobjectowner ''?'', ''' + #new + ''''
EXECUTE sp_MSforeachtable #sql
I need to change it back by switch the old and new name parameters, but I am getting an error:
Msg 15001, Level 16, State 1, Procedure sp_changeobjectowner, Line 75
Object '[db_owner].[language_link]' does not exist or is not a valid
object for this operation.
That table does exist though and even with that old db_owner. Any way to fix this?
Here is a screenshot on how I could tell it is still owned by db_owner. Only some tables were moved back properly:
Are you sure you should be using sp_changeobjectowner? (Objects don't really have owners anymore as of SQL 2005.) How did you verify that db_owner.language_link exists? Personally I would use ALTER SCHEMA for this and I would also lean toward catalog views (sys.tables) rather than information_schema.tables. Finally, I wouldn't use the undocumented and unsupported sp_MSforeachtable - I have highlighted issues with sp_MSforeachdb that are likely potential issues here because the code is quite similar.
DECLARE
#old SYSNAME = N'db_owner',
#new SYSNAME = N'dbo',
#sql NVARCHAR(MAX) = N'';
SELECT #sql += CHAR(13) + CHAR(10) + 'ALTER SCHEMA ' + #new
+ ' TRANSFER ' + QUOTENAME(SCHEMA_NAME([schema_id]))
+ '.' + QUOTENAME(name) + ';'
FROM sys.tables AS t
WHERE SCHEMA_NAME([schema_id]) = #old
AND NOT EXISTS (SELECT 1 FROM sys.tables WHERE name = t.name
AND SCHEMA_NAME([schema_id]) = #new);
PRINT #sql;
--EXEC sp_executesql #sql;
EDIT adding code to find objects that are common to both schemas. And to move the ones already in the new schema to some dummy schema:
CREATE SCHEMA dummy AUTHORIZATION dbo;
GO
DECLARE
#old SYSNAME = N'db_owner',
#new SYSNAME = N'dbo',
#sql NVARCHAR(MAX) = N'';
SELECT #sql += CHAR(13) + CHAR(10) + 'ALTER SCHEMA dummy TRANSFER '
+ QUOTENAME(#new) + '.' + QUOTENAME(t1.name) + ';'
FROM sys.tables AS t1
INNER JOIN sys.tables AS t2
ON t1.name = t2.name
WHERE t1.schema_id = SCHEMA_ID(#new)
AND t2.schema_id = SCHEMA_ID(#old);
PRINT #sql;
-- EXEC sp_executesql #sql;
But really it just sounds like you messed something up and it requires some manual cleanup...
EDIT adding evidence because OP seems convinced that this code is not working because it is not possible to move things into the dbo schema. No, that is not the case, it's just not possible to move dummy.floob -> dbo.floob if there's already an object named dbo.floob. Note that it may not be a table!
CREATE DATABASE schema_test;
GO
USE schema_test;
GO
CREATE SCHEMA floob AUTHORIZATION dbo;
GO
CREATE TABLE dbo.x(a INT);
CREATE TABLE dbo.y(a INT);
GO
Move all tables from dbo -> floob:
DECLARE
#old SYSNAME = N'dbo',
#new SYSNAME = N'floob',
#sql NVARCHAR(MAX) = N'';
SELECT #sql += CHAR(13) + CHAR(10) + 'ALTER SCHEMA ' + #new
+ ' TRANSFER ' + QUOTENAME(SCHEMA_NAME([schema_id]))
+ '.' + QUOTENAME(name) + ';'
FROM sys.tables AS t
WHERE SCHEMA_NAME([schema_id]) = #old
AND NOT EXISTS (SELECT 1 FROM sys.tables WHERE name = t.name
AND SCHEMA_NAME([schema_id]) = #new);
EXEC sp_executesql #sql;
GO
SELECT SCHEMA_NAME([schema_id]),name FROM sys.tables;
Results:
Move all tables back from floob -> dbo:
DECLARE
#old SYSNAME = N'floob',
#new SYSNAME = N'dbo',
#sql NVARCHAR(MAX) = N'';
SELECT #sql += CHAR(13) + CHAR(10) + 'ALTER SCHEMA ' + #new
+ ' TRANSFER ' + QUOTENAME(SCHEMA_NAME([schema_id]))
+ '.' + QUOTENAME(name) + ';'
FROM sys.tables AS t
WHERE SCHEMA_NAME([schema_id]) = #old
AND NOT EXISTS (SELECT 1 FROM sys.tables WHERE name = t.name
AND SCHEMA_NAME([schema_id]) = #new);
EXEC sp_executesql #sql;
GO
SELECT SCHEMA_NAME([schema_id]),name FROM sys.tables;
Results:

Search for a string in all tables, rows and columns of a DB

I am lost in a big database and I am not able to find where the data I get comes from. I was wondering if it is possible with SQL Server 2005 to search for a string in all tables, rows and columns of a database?
Does anybody has an idea if it is possible and how?
This code should do it in SQL 2005, but a few caveats:
It is RIDICULOUSLY slow. I tested it on a small database that I have with only a handful of tables and it took many minutes to complete. If your database is so big that you can't understand it then this will probably be unusable anyway.
I wrote this off the cuff. I didn't put in any error handling and there might be some other sloppiness especially since I don't use cursors often. For example, I think there's a way to refresh the columns cursor instead of closing/deallocating/recreating it every time.
If you can't understand the database or don't know where stuff is coming from, then you should probably find someone who does. Even if you can find where the data is, it might be duplicated somewhere or there might be other aspects of the database that you don't understand. If no one in your company understands the database then you're in a pretty big mess.
DECLARE
#search_string VARCHAR(100),
#table_name SYSNAME,
#table_schema SYSNAME,
#column_name SYSNAME,
#sql_string VARCHAR(2000)
SET #search_string = 'Test'
DECLARE tables_cur CURSOR FOR SELECT TABLE_SCHEMA, TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE = 'BASE TABLE'
OPEN tables_cur
FETCH NEXT FROM tables_cur INTO #table_schema, #table_name
WHILE (##FETCH_STATUS = 0)
BEGIN
DECLARE columns_cur CURSOR FOR SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = #table_schema AND TABLE_NAME = #table_name AND COLLATION_NAME IS NOT NULL -- Only strings have this and they always have it
OPEN columns_cur
FETCH NEXT FROM columns_cur INTO #column_name
WHILE (##FETCH_STATUS = 0)
BEGIN
SET #sql_string = 'IF EXISTS (SELECT * FROM ' + QUOTENAME(#table_schema) + '.' + QUOTENAME(#table_name) + ' WHERE ' + QUOTENAME(#column_name) + ' LIKE ''%' + #search_string + '%'') PRINT ''' + QUOTENAME(#table_schema) + '.' + QUOTENAME(#table_name) + ', ' + QUOTENAME(#column_name) + ''''
EXECUTE(#sql_string)
FETCH NEXT FROM columns_cur INTO #column_name
END
CLOSE columns_cur
DEALLOCATE columns_cur
FETCH NEXT FROM tables_cur INTO #table_schema, #table_name
END
CLOSE tables_cur
DEALLOCATE tables_cur
I’d suggest you find yourself a 3rd party tool for this such as ApexSQL Search (there are probably others out there too but I use this one because it’s free).
If you really want to go the SQL way you can try using stored procedure created by
Sorna Kumar Muthuraj – copied code is below. Just execute this stored procedure for all tables in your schema (easy with dynamics SQL)
CREATE PROCEDURE SearchTables
#Tablenames VARCHAR(500)
,#SearchStr NVARCHAR(60)
,#GenerateSQLOnly Bit = 0
AS
/*
Parameters and usage
#Tablenames -- Provide a single table name or multiple table name with comma seperated.
If left blank , it will check for all the tables in the database
#SearchStr -- Provide the search string. Use the '%' to coin the search.
EX : X%--- will give data staring with X
%X--- will give data ending with X
%X%--- will give data containig X
#GenerateSQLOnly -- Provide 1 if you only want to generate the SQL statements without seraching the database.
By default it is 0 and it will search.
Samples :
1. To search data in a table
EXEC SearchTables #Tablenames = 'T1'
,#SearchStr = '%TEST%'
The above sample searches in table T1 with string containing TEST.
2. To search in a multiple table
EXEC SearchTables #Tablenames = 'T2'
,#SearchStr = '%TEST%'
The above sample searches in tables T1 & T2 with string containing TEST.
3. To search in a all table
EXEC SearchTables #Tablenames = '%'
,#SearchStr = '%TEST%'
The above sample searches in all table with string containing TEST.
4. Generate the SQL for the Select statements
EXEC SearchTables #Tablenames = 'T1'
,#SearchStr = '%TEST%'
,#GenerateSQLOnly = 1
*/
SET NOCOUNT ON
DECLARE #CheckTableNames Table
(
Tablename sysname
)
DECLARE #SQLTbl TABLE
(
Tablename SYSNAME
,WHEREClause VARCHAR(MAX)
,SQLStatement VARCHAR(MAX)
,Execstatus BIT
)
DECLARE #sql VARCHAR(MAX)
DECLARE #tmpTblname sysname
IF LTRIM(RTRIM(#Tablenames)) IN ('' ,'%')
BEGIN
INSERT INTO #CheckTableNames
SELECT Name
FROM sys.tables
END
ELSE
BEGIN
SELECT #sql = 'SELECT ''' + REPLACE(#Tablenames,',',''' UNION SELECT ''') + ''''
INSERT INTO #CheckTableNames
EXEC(#sql)
END
INSERT INTO #SQLTbl
( Tablename,WHEREClause)
SELECT SCh.name + '.' + ST.NAME,
(
SELECT '[' + SC.name + ']' + ' LIKE ''' + #SearchStr + ''' OR ' + CHAR(10)
FROM SYS.columns SC
JOIN SYS.types STy
ON STy.system_type_id = SC.system_type_id
AND STy.user_type_id =SC.user_type_id
WHERE STY.name in ('varchar','char','nvarchar','nchar')
AND SC.object_id = ST.object_id
ORDER BY SC.name
FOR XML PATH('')
)
FROM SYS.tables ST
JOIN #CheckTableNames chktbls
ON chktbls.Tablename = ST.name
JOIN SYS.schemas SCh
ON ST.schema_id = SCh.schema_id
WHERE ST.name <> 'SearchTMP'
GROUP BY ST.object_id, SCh.name + '.' + ST.NAME ;
UPDATE #SQLTbl
SET SQLStatement = 'SELECT * INTO SearchTMP FROM ' + Tablename + ' WHERE ' + substring(WHEREClause,1,len(WHEREClause)-5)
DELETE FROM #SQLTbl
WHERE WHEREClause IS NULL
WHILE EXISTS (SELECT 1 FROM #SQLTbl WHERE ISNULL(Execstatus ,0) = 0)
BEGIN
SELECT TOP 1 #tmpTblname = Tablename , #sql = SQLStatement
FROM #SQLTbl
WHERE ISNULL(Execstatus ,0) = 0
IF #GenerateSQLOnly = 0
BEGIN
IF OBJECT_ID('SearchTMP','U') IS NOT NULL
DROP TABLE SearchTMP
EXEC (#SQL)
IF EXISTS(SELECT 1 FROM SearchTMP)
BEGIN
SELECT Tablename=#tmpTblname,* FROM SearchTMP
END
END
ELSE
BEGIN
PRINT REPLICATE('-',100)
PRINT #tmpTblname
PRINT REPLICATE('-',100)
PRINT replace(#sql,'INTO SearchTMP','')
END
UPDATE #SQLTbl
SET Execstatus = 1
WHERE Tablename = #tmpTblname
END
SET NOCOUNT OFF
go
Although the solutions presented before are valid and work, I humbly offer a code that's cleaner, more elegant, and with better performance, at least as I see it.
Firstly, one may ask: Why would anyone ever need a code snippet to globally and blindly look for a string? Hey, they already invented fulltext, don't you know?
My answer: my mainly work is at systems integration projects, and discovering where the data is written is important whenever I'm learning a new and undocummented database, which seldom happens.
Also, the code I present is a stripped down version of a more powerful and dangerous script that searches and REPLACES text throughout the database.
CREATE TABLE #result(
id INT IDENTITY, -- just for register seek order
tblName VARCHAR(255),
colName VARCHAR(255),
qtRows INT
)
go
DECLARE #toLookFor VARCHAR(255)
SET #toLookFor = '[input your search criteria here]'
DECLARE cCursor CURSOR LOCAL FAST_FORWARD FOR
SELECT
'[' + usr.name + '].[' + tbl.name + ']' AS tblName,
'[' + col.name + ']' AS colName,
LOWER(typ.name) AS typName
FROM
sysobjects tbl
INNER JOIN(
syscolumns col
INNER JOIN systypes typ
ON typ.xtype = col.xtype
)
ON col.id = tbl.id
--
LEFT OUTER JOIN sysusers usr
ON usr.uid = tbl.uid
WHERE tbl.xtype = 'U'
AND LOWER(typ.name) IN(
'char', 'nchar',
'varchar', 'nvarchar',
'text', 'ntext'
)
ORDER BY tbl.name, col.colorder
--
DECLARE #tblName VARCHAR(255)
DECLARE #colName VARCHAR(255)
DECLARE #typName VARCHAR(255)
--
DECLARE #sql NVARCHAR(4000)
DECLARE #crlf CHAR(2)
SET #crlf = CHAR(13) + CHAR(10)
OPEN cCursor
FETCH cCursor
INTO #tblName, #colName, #typName
WHILE ##fetch_status = 0
BEGIN
IF #typName IN('text', 'ntext')
BEGIN
SET #sql = ''
SET #sql = #sql + 'INSERT INTO #result(tblName, colName, qtRows)' + #crlf
SET #sql = #sql + 'SELECT #tblName, #colName, COUNT(*)' + #crlf
SET #sql = #sql + 'FROM ' + #tblName + #crlf
SET #sql = #sql + 'WHERE PATINDEX(''%'' + #toLookFor + ''%'', ' + #colName + ') > 0' + #crlf
END
ELSE
BEGIN
SET #sql = ''
SET #sql = #sql + 'INSERT INTO #result(tblName, colName, qtRows)' + #crlf
SET #sql = #sql + 'SELECT #tblName, #colName, COUNT(*)' + #crlf
SET #sql = #sql + 'FROM ' + #tblName + #crlf
SET #sql = #sql + 'WHERE ' + #colName + ' LIKE ''%'' + #toLookFor + ''%''' + #crlf
END
EXECUTE sp_executesql
#sql,
N'#tblName varchar(255), #colName varchar(255), #toLookFor varchar(255)',
#tblName, #colName, #toLookFor
FETCH cCursor
INTO #tblName, #colName, #typName
END
SELECT *
FROM #result
WHERE qtRows > 0
ORDER BY id
GO
DROP TABLE #result
go
If you are "getting data" from an application, the sensible thing would be to use the profiler and profile the database while running the application. Trace it, then search the results for that string.
The SSMS Tools PACK Add-In (Add-On) for Microsoft SQL Server Management Studio and Microsoft SQL Server Management Studio Express will do exactly what you need. On larger database it takes some time to search, but that is to be expected. It also includes a ton of cool features that should have be included with SQL Server Management Studio in the first place. Give it a try www.ssmstoolspack.com/
You do need to have SP2 for SQL Server Management Studio installed to run the tools.
I adapted a script originally written by Narayana Vyas Kondreddi in 2002. I changed the where clause to check text/ntext fields as well, by using patindex rather than like. I also changed the results table slightly. Unreasonably, I changed variable names, and aligned as I prefer (no disrespect to Mr. Kondretti). The user may want to change the data types searched. I used a global table to allow querying mid-processing, but a permanent table might be a smarter way to go.
/* original script by Narayana Vyas Kondreddi, 2002 */
/* adapted by Oliver Holloway, 2009 */
/* these lines can be replaced by use of input parameter for a proc */
declare #search_string varchar(1000);
set #search_string = 'what.you.are.searching.for';
/* create results table */
create table ##string_locations (
table_name varchar(1000),
field_name varchar(1000),
field_value varchar(8000)
)
;
/* special settings */
set nocount on
;
/* declare variables */
declare
#table_name varchar(1000),
#field_name varchar(1000)
;
/* variable settings */
set #table_name = ''
;
set #search_string = QUOTENAME('%' + #search_string + '%','''')
;
/* for each table */
while #table_name is not null
begin
set #field_name = ''
set #table_name = (
select MIN(QUOTENAME(table_schema) + '.' + QUOTENAME(table_name))
from INFORMATION_SCHEMA.TABLES
where
table_type = 'BASE TABLE' and
QUOTENAME(table_schema) + '.' + QUOTENAME(table_name) > #table_name and
OBJECTPROPERTY(OBJECT_ID(QUOTENAME(table_schema) + '.' + QUOTENAME(table_name)), 'IsMSShipped') = 0
)
/* for each string-ish field */
while (#table_name is not null) and (#field_name is not null)
begin
set #field_name = (
select MIN(QUOTENAME(column_name))
from INFORMATION_SCHEMA.COLUMNS
where
table_schema = PARSENAME(#table_name, 2) and
table_name = PARSENAME(#table_name, 1) and
data_type in ('char', 'varchar', 'nchar', 'nvarchar', 'text', 'ntext') and
QUOTENAME(column_name) > #field_name
)
/* search that field for the string supplied */
if #field_name is not null
begin
insert into ##string_locations
exec(
'select ''' + #table_name + ''',''' + #field_name + ''',' + #field_name +
'from ' + #table_name + ' (nolock) ' +
'where patindex(' + #search_string + ',' + #field_name + ') > 0' /* patindex works with char & text */
)
end
;
end
;
end
;
/* return results */
select table_name, field_name, field_value from ##string_locations (nolock)
;
/* drop temp table */
--drop table ##string_locations
;
Other answers posted already may work equally well or better, but I haven't used them. However, the following SQL I have used, and it really helped me out when I was trying to reverse-engineer a big system with a huge (and very unorganzied) SQL Server database.
This isn't my code. I wish I could credit the original author, but I can't find the link to the article anymore :(
Use
go
declare #SearchChar varchar(8000)
Set #SearchChar = -- Like 'A%', '11/11/2006'
declare #CMDMain varchar(8000), #CMDMainCount varchar(8000),#CMDJoin varchar(8000)
declare #ColumnName varchar(100),#TableName varchar(100)
declare dbTable cursor for
SELECT
Distinct b.Name as TableName
FROM
sysobjects b
WHERE
b.type='u' and b.Name 'dtproperties'
order by b.name
open dbTable
fetch next from dbTable into #TableName
WHILE ##FETCH_STATUS = 0
BEGIN
declare db cursor for
SELECT
c.Name as ColumnName
FROM
sysobjects b,
syscolumns c
WHERE
C.id = b.id and
b.type='u' and b.Name = #TableName
order by b.name
open db
fetch next from db into #ColumnName
set #CMDMain = 'SELECT ' + char(39) + #TableName + char(39) + ' as TableName,'+
' ['+ #TableName + '].* FROM [' + #TableName + ']'+
' WHERE '
set #CMDMainCount = 'SELECT Count(*) FROM [' + #TableName + '] Where '
Set #CMDJoin = ''
WHILE ##FETCH_STATUS = 0
BEGIN
set #CMDJoin = #CMDJoin + 'Convert(varchar(5000),[' +#ColumnName + ']) like ' + char(39) + #SearchChar + char(39) + ' OR '
fetch next from db into #ColumnName
end
close db
deallocate db
Set #CMDMainCount = 'If ('+ #CMDMainCount + Left(#CMDJoin, len(#CMDJoin) - 3)+ ') > 0 Begin '
Set #CMDMain = #CMDMainCount + #CMDMain + Left(#CMDJoin, len(#CMDJoin) - 3)
Set #CMDMain = #CMDMain + ' End '
Print #CMDMain
exec (#CMDMain)
fetch next from dbTable into #TableName
end
close dbTable
deallocate dbTable
Actually Im agree with MikeW (+1) it's better to use profiler for this case.
Anyway, if you really need to grab all (n)varchar columns in db and make a search. See below.
I suppose to use INFORMATION_SCHEMA.Tables + dynamic SQL.
The plain search:
DECLARE #SearchText VARCHAR(100)
SET #SearchText = '12'
DECLARE #Tables TABLE(N INT, TableName VARCHAR(100), ColumnNamesCSV VARCHAR(2000), SQL VARCHAR(4000))
INSERT INTO #Tables (TableName, ColumnNamesCSV)
SELECT T.TABLE_NAME AS TableName,
( SELECT C.Column_Name + ','
FROM INFORMATION_SCHEMA.Columns C
WHERE T.TABLE_NAME = C.TABLE_NAME
AND C.DATA_TYPE IN ('nvarchar','varchar')
FOR XML PATH('')
)
FROM INFORMATION_SCHEMA.Tables T
DELETE FROM #Tables WHERE ColumnNamesCSV IS NULL
INSERT INTO #Tables (N, TableName, ColumnNamesCSV)
SELECT ROW_NUMBER() OVER(ORDER BY TableName), TableName, ColumnNamesCSV
FROM #Tables
DELETE FROM #Tables WHERE N IS NULL
UPDATE #Tables
SET ColumnNamesCSV = SUBSTRING(ColumnNamesCSV, 0, LEN(ColumnNamesCSV))
UPDATE #Tables
SET SQL = 'SELECT * FROM ['+TableName+'] WHERE '''+#SearchText+''' IN ('+ColumnNamesCSV+')'
DECLARE #C INT,
#I INT,
#SQL VARCHAR(4000)
SELECT #I = 1,
#C = COUNT(1)
FROM #Tables
WHILE #I <= #C BEGIN
SELECT #SQL = SQL FROM #Tables WHERE N = #I
SET #I = #I+1
EXEC(#SQL)
END
and one with LIKE clause:
DECLARE #SearchText VARCHAR(100)
SET #SearchText = '12'
DECLARE #Tables TABLE(N INT, TableName VARCHAR(100), ColumnNamesCSVLike VARCHAR(2000), LIKESQL VARCHAR(4000))
INSERT INTO #Tables (TableName, ColumnNamesCSVLike)
SELECT T.TABLE_NAME AS TableName,
( SELECT C.Column_Name + ' LIKE ''%'+#SearchText+'%'' OR '
FROM INFORMATION_SCHEMA.Columns C
WHERE T.TABLE_NAME = C.TABLE_NAME
AND C.DATA_TYPE IN ('nvarchar','varchar')
FOR XML PATH(''))
FROM INFORMATION_SCHEMA.Tables T
DELETE FROM #Tables WHERE ColumnNamesCSVLike IS NULL
INSERT INTO #Tables (N, TableName, ColumnNamesCSVLike)
SELECT ROW_NUMBER() OVER(ORDER BY TableName), TableName, ColumnNamesCSVLike
FROM #Tables
DELETE FROM #Tables WHERE N IS NULL
UPDATE #Tables
SET ColumnNamesCSVLike = SUBSTRING(ColumnNamesCSVLike, 0, LEN(ColumnNamesCSVLike)-2)
UPDATE #Tables SET LIKESQL = 'SELECT * FROM ['+TableName+'] WHERE '+ColumnNamesCSVLike
DECLARE #C INT,
#I INT,
#LIKESQL VARCHAR(4000)
SELECT #I = 1,
#C = COUNT(1)
FROM #Tables
WHILE #I <= #C BEGIN
SELECT #LIKESQL = LIKESQL FROM #Tables WHERE N = #I
SET #I = #I +1
EXEC(#LIKESQL)
END
#NLwino, yery good query with a few errors for keyword usage. I had to modify it a little to wrap the keywords with [ ] and also look char and ntext columns.
DECLARE #searchstring NVARCHAR(255)
SET #searchstring = '%WDB1014%'
DECLARE #sql NVARCHAR(max)
SELECT #sql = STUFF((
SELECT ' UNION ALL SELECT ''' + TABLE_NAME + ''' AS tbl, ''' + COLUMN_NAME + ''' AS col, [' + COLUMN_NAME + '] AS val' +
' FROM ' + TABLE_SCHEMA + '.[' + TABLE_NAME +
'] WHERE [' + COLUMN_NAME + '] LIKE ''' + #searchstring + ''''
FROM INFORMATION_SCHEMA.COLUMNS
WHERE DATA_TYPE in ('nvarchar', 'varchar', 'char', 'ntext')
FOR XML PATH('')
) ,1, 11, '')
Exec (#sql)
I ran it on 2.5 GB database and it came back in 51 seconds
I think this can be an easiest way to find a string in all rows of your database -without using cursors and FOR XML-.
CREATE PROCEDURE SPFindAll (#find VARCHAR(max) = '')
AS
BEGIN
SET NOCOUNT ON;
--
DECLARE #query VARCHAR(max) = ''
SELECT #query = #query +
CASE
WHEN #query = '' THEN ''
ELSE ' UNION ALL '
END +
'SELECT ''' + s.name + ''' As schemaName, ''' + t.name + ''' As tableName, ''' + c.name + ''' As ColumnName, [' + c.name + '] COLLATE DATABASE_DEFAULT As [Data] FROM [' + s.name + '].[' + t.name + '] WHERE [' + c.name + '] Like ''%' + #find + '%'''
FROM
sys.schemas s
INNER JOIN
sys.tables t ON s.[schema_id] = t.[schema_id]
INNER JOIN
sys.columns c ON t.[object_id] = c.[object_id]
INNER JOIN
sys.types ty ON c.user_type_id = ty.user_type_id
WHERE
ty.name LIKE '%char'
EXEC(#query)
END
By creating this stored procedure you can run it for any string you want to find like this:
EXEC SPFindAll 'Hello World'
The result will be like this:
schemaName | tableName | columnName | Data
-----------+-----------+------------+-----------------------
schema1 | Table1 | Column1 | Hello World
schema1 | Table1 | Column1 | Hello World!
schema1 | Table2 | Column1 | I say "Hello World".
schema1 | Table2 | Column2 | Hello World
This uses no cursors or anything like that, just one dynamic query.
Also note that this uses LIKE. Since that happened to be what I needed. It works for all schemas, all tables and only query's those columns that are NVARCHAR or VARCHAR even if they have UDDT.
DECLARE #searchstring NVARCHAR(255)
SET #searchstring = '%searchstring%'
DECLARE #sql NVARCHAR(max)
SELECT #sql = STUFF((
SELECT ' UNION ALL SELECT ''' + TABLE_NAME + ''' AS tablename, ''' + COLUMN_NAME + ''' AS columnname, ' + COLUMN_NAME + ' AS valuename' +
' FROM ' + TABLE_SCHEMA + '.' + TABLE_NAME +
' WHERE ' + COLUMN_NAME + ' LIKE ''' + #searchstring + ''''
FROM INFORMATION_SCHEMA.COLUMNS
WHERE DATA_TYPE in ('nvarchar', 'varchar')
FOR XML PATH('')
) ,1, 11, '')
EXEC(#sql)
The output gives you the table, column and value. Time to execute on a small database was ~3 seconds, had about 3000 results.
/*
This procedure is for finding any string or date in all tables
if search string is date, its format should be yyyy-MM-dd
eg. 2011-07-05
*/
-- ================================================
-- Exec SearchInTables 'f6f56934-a5d4-4967-80a1-1a2223b9c7b1'
-- ================================================
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
-- =============================================
-- Author: <Joshy,,Name>
-- Create date: <Create Date,,>
-- Description: <Description,,>
-- =============================================
ALTER PROCEDURE SearchInTables
#myValue nvarchar(1000)
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
-- Insert statements for procedure here
DECLARE #searchsql nvarchar(max)
DECLARE #table_name nvarchar(1000)
DECLARE #Schema_name nvarchar(1000)
DECLARE #ParmDefinition nvarchar(500)
DECLARE #XMLIn nvarchar(max)
SET #ParmDefinition = N'#XMLOut varchar(max) OUTPUT'
SELECT A.name,b.name
FROM sys.tables A
INNER JOIN sys.schemas B ON A.schema_id=B.schema_id
WHERE A.name like 'tbl_Tax_Sections'
DECLARE tables_cur CURSOR FOR
SELECT A.name,b.name FOM sys.tables A
INNER JOIN sys.schemas B ON A.schema_id=B.schema_id
WHERE A.type = 'U'
OPEN tables_cur
FETCH NEXT FROM tables_cur INTO #table_name , #Schema_name
WHILE (##FETCH_STATUS = 0)
BEGIN
SET #searchsql ='SELECT #XMLOut=(SELECT PATINDEX(''%'+ #myValue+ '%'''
SET #searchsql =#searchsql + ', (SELECT * FROM '+#Schema_name+'.'+#table_name+' FOR XML AUTO) ))'
--print #searchsql
EXEC sp_executesql #searchsql, #ParmDefinition, #XMLOut=#XMLIn OUTPUT
--print #XMLIn
IF #XMLIn <> 0 PRINT #Schema_name+'.'+#table_name
FETCH NEXT FROM tables_cur INTO #table_name , #Schema_name
END
CLOSE tables_cur
DEALLOCATE tables_cur
RETURN
END
GO
To "find where the data I get comes from", you can start SQL Profiler, start your report or application, and you will see all the queries issued against your database.
Or, you can use my query here, should be simpler then having to create sProcs for each DB you want to search: FullParam SQL Blog
/* Reto Egeter, fullparam.wordpress.com */
DECLARE #SearchStrTableName nvarchar(255), #SearchStrColumnName nvarchar(255), #SearchStrColumnValue nvarchar(255), #SearchStrInXML bit, #FullRowResult bit, #FullRowResultRows int
SET #SearchStrColumnValue = '%searchthis%' /* use LIKE syntax */
SET #FullRowResult = 1
SET #FullRowResultRows = 3
SET #SearchStrTableName = NULL /* NULL for all tables, uses LIKE syntax */
SET #SearchStrColumnName = NULL /* NULL for all columns, uses LIKE syntax */
SET #SearchStrInXML = 0 /* Searching XML data may be slow */
IF OBJECT_ID('tempdb..#Results') IS NOT NULL DROP TABLE #Results
CREATE TABLE #Results (TableName nvarchar(128), ColumnName nvarchar(128), ColumnValue nvarchar(max),ColumnType nvarchar(20))
SET NOCOUNT ON
DECLARE #TableName nvarchar(256) = '',#ColumnName nvarchar(128),#ColumnType nvarchar(20), #QuotedSearchStrColumnValue nvarchar(110), #QuotedSearchStrColumnName nvarchar(110)
SET #QuotedSearchStrColumnValue = QUOTENAME(#SearchStrColumnValue,'''')
DECLARE #ColumnNameTable TABLE (COLUMN_NAME nvarchar(128),DATA_TYPE nvarchar(20))
WHILE #TableName IS NOT NULL
BEGIN
SET #TableName =
(
SELECT MIN(QUOTENAME(TABLE_SCHEMA) + '.' + QUOTENAME(TABLE_NAME))
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_TYPE = 'BASE TABLE'
AND TABLE_NAME LIKE COALESCE(#SearchStrTableName,TABLE_NAME)
AND QUOTENAME(TABLE_SCHEMA) + '.' + QUOTENAME(TABLE_NAME) > #TableName
AND OBJECTPROPERTY(OBJECT_ID(QUOTENAME(TABLE_SCHEMA) + '.' + QUOTENAME(TABLE_NAME)), 'IsMSShipped') = 0
)
IF #TableName IS NOT NULL
BEGIN
DECLARE #sql VARCHAR(MAX)
SET #sql = 'SELECT QUOTENAME(COLUMN_NAME),DATA_TYPE
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_SCHEMA = PARSENAME(''' + #TableName + ''', 2)
AND TABLE_NAME = PARSENAME(''' + #TableName + ''', 1)
AND DATA_TYPE IN (' + CASE WHEN ISNUMERIC(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(#SearchStrColumnValue,'%',''),'_',''),'[',''),']',''),'-','')) = 1 THEN '''tinyint'',''int'',''smallint'',''bigint'',''numeric'',''decimal'',''smallmoney'',''money'',' ELSE '' END + '''char'',''varchar'',''nchar'',''nvarchar'',''timestamp'',''uniqueidentifier''' + CASE #SearchStrInXML WHEN 1 THEN ',''xml''' ELSE '' END + ')
AND COLUMN_NAME LIKE COALESCE(' + CASE WHEN #SearchStrColumnName IS NULL THEN 'NULL' ELSE '''' + #SearchStrColumnName + '''' END + ',COLUMN_NAME)'
INSERT INTO #ColumnNameTable
EXEC (#sql)
WHILE EXISTS (SELECT TOP 1 COLUMN_NAME FROM #ColumnNameTable)
BEGIN
PRINT #ColumnName
SELECT TOP 1 #ColumnName = COLUMN_NAME,#ColumnType = DATA_TYPE FROM #ColumnNameTable
SET #sql = 'SELECT ''' + #TableName + ''',''' + #ColumnName + ''',' + CASE #ColumnType WHEN 'xml' THEN 'LEFT(CAST(' + #ColumnName + ' AS nvarchar(MAX)), 4096),'''
WHEN 'timestamp' THEN 'master.dbo.fn_varbintohexstr('+ #ColumnName + '),'''
ELSE 'LEFT(' + #ColumnName + ', 4096),''' END + #ColumnType + '''
FROM ' + #TableName + ' (NOLOCK) ' +
' WHERE ' + CASE #ColumnType WHEN 'xml' THEN 'CAST(' + #ColumnName + ' AS nvarchar(MAX))'
WHEN 'timestamp' THEN 'master.dbo.fn_varbintohexstr('+ #ColumnName + ')'
ELSE #ColumnName END + ' LIKE ' + #QuotedSearchStrColumnValue
INSERT INTO #Results
EXEC(#sql)
IF ##ROWCOUNT > 0 IF #FullRowResult = 1
BEGIN
SET #sql = 'SELECT TOP ' + CAST(#FullRowResultRows AS VARCHAR(3)) + ' ''' + #TableName + ''' AS [TableFound],''' + #ColumnName + ''' AS [ColumnFound],''FullRow>'' AS [FullRow>],*' +
' FROM ' + #TableName + ' (NOLOCK) ' +
' WHERE ' + CASE #ColumnType WHEN 'xml' THEN 'CAST(' + #ColumnName + ' AS nvarchar(MAX))'
WHEN 'timestamp' THEN 'master.dbo.fn_varbintohexstr('+ #ColumnName + ')'
ELSE #ColumnName END + ' LIKE ' + #QuotedSearchStrColumnValue
EXEC(#sql)
END
DELETE FROM #ColumnNameTable WHERE COLUMN_NAME = #ColumnName
END
END
END
SET NOCOUNT OFF
SELECT TableName, ColumnName, ColumnValue, ColumnType, COUNT(*) AS Count FROM #Results
GROUP BY TableName, ColumnName, ColumnValue, ColumnType
This query can do the thing for you.
DECLARE
#search_string VARCHAR(100),
#table_name SYSNAME,
#table_id INT,
#column_name SYSNAME,
#sql_string VARCHAR(2000)
SET #search_string = 'StringtoSearch'
DECLARE tables_cur CURSOR FOR SELECT ss.name +'.'+ so.name [name], object_id FROM sys.objects so INNER JOIN sys.schemas ss ON so.schema_id = ss.schema_id WHERE type = 'U'
OPEN tables_cur
FETCH NEXT FROM tables_cur INTO #table_name, #table_id
WHILE (##FETCH_STATUS = 0)
BEGIN
DECLARE columns_cur CURSOR FOR SELECT name FROM sys.columns WHERE object_id = #table_id
AND system_type_id IN (167, 175, 231, 239, 99)
OPEN columns_cur
FETCH NEXT FROM columns_cur INTO #column_name
WHILE (##FETCH_STATUS = 0)
BEGIN
SET #sql_string = 'IF EXISTS (SELECT * FROM ' + #table_name + ' WHERE [' + #column_name + ']
LIKE ''%' + #search_string + '%'') PRINT ''' + #table_name + ', ' + #column_name + ''''
EXECUTE(#sql_string)
FETCH NEXT FROM columns_cur INTO #column_name
END
CLOSE columns_cur
DEALLOCATE columns_cur
FETCH NEXT FROM tables_cur INTO #table_name, #table_id
END
CLOSE tables_cur
DEALLOCATE tables_cur

How do I do a simple 'Find and Replace" in MsSQL?

Question is pretty self explanitory. I want to do a simple find and replace, like you would in a text editor on the data in a column of my database (which is MsSQL on MS Windows server 2003)
The following query replace each and every a character with a b character.
UPDATE
YourTable
SET
Column1 = REPLACE(Column1,'a','b')
WHERE
Column1 LIKE '%a%'
This will not work on SQL server 2003.
like so:
BEGIN TRANSACTION;
UPDATE table_name
SET column_name=REPLACE(column_name,'text_to_find','replace_with_this');
COMMIT TRANSACTION;
Example: Replaces <script... with <a ... to eliminate javascript vulnerabilities
BEGIN TRANSACTION; UPDATE testdb
SET title=REPLACE(title,'script','a'); COMMIT TRANSACTION;
This pointed me in the right direction, but I have a DB that originated in MSSQL 2000 and is still using the ntext data type for the column I was replacing on. When you try to run REPLACE on that type you get this error:
Argument data type ntext is invalid for argument 1 of replace
function.
The simplest fix, if your column data fits within nvarchar, is to cast the column during replace. Borrowing the code from the accepted answer:
UPDATE YourTable
SET Column1 = REPLACE(cast(Column1 as nvarchar(max)),'a','b')
WHERE Column1 LIKE '%a%'
This worked perfectly for me. Thanks to this forum post I found for the fix. Hopefully this helps someone else!
The following will find and replace a string in every database (excluding system databases) on every table on the instance you are connected to:
Simply change 'Search String' to whatever you seek and 'Replace String' with whatever you want to replace it with.
--Getting all the databases and making a cursor
DECLARE db_cursor CURSOR FOR
SELECT name
FROM master.dbo.sysdatabases
WHERE name NOT IN ('master','model','msdb','tempdb') -- exclude these databases
DECLARE #databaseName nvarchar(1000)
--opening the cursor to move over the databases in this instance
OPEN db_cursor
FETCH NEXT FROM db_cursor INTO #databaseName
WHILE ##FETCH_STATUS = 0
BEGIN
PRINT #databaseName
--Setting up temp table for the results of our search
DECLARE #Results TABLE(TableName nvarchar(370), RealColumnName nvarchar(370), ColumnName nvarchar(370), ColumnValue nvarchar(3630))
SET NOCOUNT ON
DECLARE #SearchStr nvarchar(100), #ReplaceStr nvarchar(100), #SearchStr2 nvarchar(110)
SET #SearchStr = 'Search String'
SET #ReplaceStr = 'Replace String'
SET #SearchStr2 = QUOTENAME('%' + #SearchStr + '%','''')
DECLARE #TableName nvarchar(256), #ColumnName nvarchar(128)
SET #TableName = ''
--Looping over all the tables in the database
WHILE #TableName IS NOT NULL
BEGIN
DECLARE #SQL nvarchar(2000)
SET #ColumnName = ''
DECLARE #result NVARCHAR(256)
SET #SQL = 'USE ' + #databaseName + '
SELECT #result = MIN(QUOTENAME(TABLE_SCHEMA) + ''.'' + QUOTENAME(TABLE_NAME))
FROM [' + #databaseName + '].INFORMATION_SCHEMA.TABLES
WHERE TABLE_TYPE = ''BASE TABLE'' AND TABLE_CATALOG = ''' + #databaseName + '''
AND QUOTENAME(TABLE_SCHEMA) + ''.'' + QUOTENAME(TABLE_NAME) > ''' + #TableName + '''
AND OBJECTPROPERTY(
OBJECT_ID(
QUOTENAME(TABLE_SCHEMA) + ''.'' + QUOTENAME(TABLE_NAME)
), ''IsMSShipped''
) = 0'
EXEC master..sp_executesql #SQL, N'#result nvarchar(256) out', #result out
SET #TableName = #result
PRINT #TableName
WHILE (#TableName IS NOT NULL) AND (#ColumnName IS NOT NULL)
BEGIN
DECLARE #ColumnResult NVARCHAR(256)
SET #SQL = '
SELECT #ColumnResult = MIN(QUOTENAME(COLUMN_NAME))
FROM [' + #databaseName + '].INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_SCHEMA = PARSENAME(''[' + #databaseName + '].' + #TableName + ''', 2)
AND TABLE_NAME = PARSENAME(''[' + #databaseName + '].' + #TableName + ''', 1)
AND DATA_TYPE IN (''char'', ''varchar'', ''nchar'', ''nvarchar'')
AND TABLE_CATALOG = ''' + #databaseName + '''
AND QUOTENAME(COLUMN_NAME) > ''' + #ColumnName + ''''
PRINT #SQL
EXEC master..sp_executesql #SQL, N'#ColumnResult nvarchar(256) out', #ColumnResult out
SET #ColumnName = #ColumnResult
PRINT #ColumnName
IF #ColumnName IS NOT NULL
BEGIN
INSERT INTO #Results
EXEC
(
'USE ' + #databaseName + '
SELECT ''' + #TableName + ''',''' + #ColumnName + ''',''' + #TableName + '.' + #ColumnName + ''', LEFT(' + #ColumnName + ', 3630)
FROM ' + #TableName + ' (NOLOCK) ' +
' WHERE ' + #ColumnName + ' LIKE ' + #SearchStr2
)
END
END
END
--Declaring another temporary table
DECLARE #time_to_update TABLE(TableName nvarchar(370), RealColumnName nvarchar(370))
INSERT INTO #time_to_update
SELECT TableName, RealColumnName FROM #Results GROUP BY TableName, RealColumnName
DECLARE #MyCursor CURSOR;
BEGIN
DECLARE #t nvarchar(370)
DECLARE #c nvarchar(370)
--Looping over the search results
SET #MyCursor = CURSOR FOR
SELECT TableName, RealColumnName FROM #time_to_update GROUP BY TableName, RealColumnName
--Getting my variables from the first item
OPEN #MyCursor
FETCH NEXT FROM #MyCursor
INTO #t, #c
WHILE ##FETCH_STATUS = 0
BEGIN
-- Updating the old values with the new value
DECLARE #sqlCommand varchar(1000)
SET #sqlCommand = '
USE ' + #databaseName + '
UPDATE [' + #databaseName + '].' + #t + ' SET ' + #c + ' = REPLACE(' + #c + ', ''' + #SearchStr + ''', ''' + #ReplaceStr + ''')
WHERE ' + #c + ' LIKE ''' + #SearchStr2 + ''''
PRINT #sqlCommand
BEGIN TRY
EXEC (#sqlCommand)
END TRY
BEGIN CATCH
PRINT ERROR_MESSAGE()
END CATCH
--Getting next row values
FETCH NEXT FROM #MyCursor
INTO #t, #c
END;
CLOSE #MyCursor ;
DEALLOCATE #MyCursor;
END;
DELETE FROM #time_to_update
DELETE FROM #Results
FETCH NEXT FROM db_cursor INTO #databaseName
END
CLOSE db_cursor
DEALLOCATE db_cursor
Note: this isn't ideal, nor is it optimized
If you are working with SQL Server 2005 or later there is also a CLR library available at http://www.sqlsharp.com/ that provides .NET implementations of string and RegEx functions which, depending on your volume and type of data may be easier to use and in some cases the .NET string manipulation functions can be more efficient than T-SQL ones.