How to iterate through tables in a schema with Dynamic Sql - sql

I have a database of tables, and i want to iterate through each table in 3 different schema, one schema at a time.
I figure that i'll need something along the lines of :
DECLARE #tableName varchar(50)
DECLARE #schemaName varchar(50)
For now lets call the schemas "A" "B" and "C".
I can get a list of the tables from each schema using :
SELECT t.name
FROM sys.tables AS t
INNER JOIN sys.schemas AS s
ON t.[schema_id] = s.[schema_id]
WHERE s.name = N'schema_name';
but im not sure how to iterate through that list (id like to insert values in to every table one by one, and they are dependent on the datatype of the columns of the tables so i cant just do a blanket insert into all statement).

DECLARE #SchemaName SYSNAME = 'dbo'
DECLARE #TableName SYSNAME
--note sysname is the same thing as NVARCHAR()
DECLARE CursorName CURSOR FOR
SELECT t.name
FROM sys.tables AS t
INNER JOIN sys.schemas AS s
ON t.[schema_id] = s.[schema_id]
WHERE s.name = #SchemaName;
OPEN CursorName
FETCH NEXT FROM CursorName
INTO #TableName
WHILE ##FETCH_STATUS = 0
BEGIN
DECLARE #Columns NVARCHAR(MAX)
SET #Columns =
STUFF(
(SELECT
',' + QUOTENAME(name)
FROM
sys.columns
WHERE
object_id = OBJECT_ID(QUOTENAME(#SchemaName) + '.' + QUOTENAME(#TableName))
FOR XML PATH(''))
,1,1,'')
DECLARE #SQL AS NVARCHAR(MAX)
SET #SQL = 'INSERT INTO ' + QUOTENAME(#SchemaName) + '.' + QUOTENAME(#TableName) +
' (' + #Columns + ') VALUES (' +
'YOU MAKE REST DEPENDING ON YOUR NEEDS'
--use print to view and copy your dynamic sql string to see if you have formed it correctly
PRINT #SQL
--EXECUTE (#SQL)
FETCH NEXT FROM CursorName
INTO #TableName
END
CLOSE CursorName
DEALLOCATE CursorName

Related

Search table columns for values over a certain length

So I have a database with many tables that have a column that contains a GL Account value (for financial purposes). The column name varies by table (i.e. in one table the column is called "gldebitaccount" and in another table it's called "glcreditaccount"). I was able to find all combinations of table / column pairs using the following query:
SELECT c.name AS ColName, t.name AS TableName
FROM sys.columns c
JOIN sys.tables t ON c.object_id = t.object_id
WHERE c.name LIKE '%gl%acc%'
This query returns close to 100 pairs of tables/columns. I am trying to find any value in any of those table/column pairs that exceeds 25 chars in length. For an individual table/column, I'd typically use:
SELECT *
FROM tableName
WHERE LEN(columnName)>25
I want to avoid having to run that query 100 times with each pair. Is there any way I can do a "for each" (which I know is frowned upon in SQL since everything should be set-based). I've done sub-SELECT statements before, but not any that involved change the table in the FROM clause. Any ideas or help would be greatly appreciated!
Thanks in advance!
As the previous answer, the solution will need dynamic SQL. Here is a way that uses both dynamic SQL and cursors, and you can expect slow performance, so use at your own risk:
DECLARE #TableName NVARCHAR(128), #ColumnName NVARCHAR(128)
DECLARE #Query NVARCHAR(4000)
DECLARE CC CURSOR LOCAL FAST_FORWARD FOR
SELECT QUOTENAME(t.name), QUOTENAME(c.name)
FROM sys.columns c
INNER JOIN sys.tables t
ON c.object_id = t.object_id
WHERE c.collation_name IS NOT NULL
AND c.max_length > 25 AND c.name LIKE '%gl%acc%';
CREATE TABLE #Results(TableName NVARCHAR(128), ColumnName NVARCHAR(128));
OPEN CC
FETCH NEXT FROM CC INTO #TableName, #ColumnName
WHILE ##FETCH_STATUS = 0
BEGIN
SET #Query = 'IF EXISTS(SELECT 1 FROM '+#TableName+'
WHERE LEN('+#ColumnName+') > 25)
INSERT INTO #Results
VALUES(#TableName,#ColumnName)'
EXEC sp_executesql #Query,
N'#TableName NVARCHAR(128),#ColumnName NVARCHAR(128)',
#TableName,
#ColumnName;
FETCH NEXT FROM CC INTO #TableName, #ColumnName
END
CLOSE CC
DEALLOCATE CC
SELECT *
FROM #Results
Here's an option without cursors that also doesn't add XML overhead. Note that it also protects you from potential type conflicts (e.g. try the others in a database with hierarchyid columns, like AdventureWorks), from table or column names with apostrophes, and from table names that exist in more than one schema.
DECLARE #sql NVARCHAR(MAX) = N'';
CREATE TABLE #Results
(
SchemaName NVARCHAR(128), TableName NVARCHAR(128), ColumnName NVARCHAR(128)
);
SELECT #sql += N'INSERT #Results SELECT '''
+ REPLACE(s.name,'''','''''') + ''','''
+ REPLACE(t.name,'''','''''') + ''','''
+ REPLACE(c.name,'''','''''') + '''
WHERE EXISTS (SELECT 1 FROM ' + QUOTENAME(s.name)
+ '.' + QUOTENAME(t.name) + ' WHERE
LEN(' + QUOTENAME(c.name) + ') > 25);
'
FROM sys.columns AS c
INNER JOIN sys.tables AS t
ON c.[object_id] = t.[object_id]
INNER JOIN sys.schemas AS s
ON t.[schema_id] = s.[schema_id]
WHERE
(
c.system_type_id IN (35,99) -- text,ntext
OR (c.system_type_id IN (167,231) -- varchar,nvarchar, could be max
AND c.max_length > 25 OR c.max_length = -1)
OR (c.system_type_id IN (175,239) -- char, nchar
AND c.max_length > 25)
)
AND c.name LIKE N'%gl%acc%';
EXEC sp_executesql #sql;
SELECT SchemaName, TableName, ColumnName FROM #Results;
Yet another solution with dynamic SQL.
But now without cursors. It uses FOR XML statement and should be much faster.
DECLARE #sqlstatement VARCHAR(MAX);
SET #sqlstatement =
REPLACE (
STUFF ( (
SELECT 'UNION ALL SELECT ''' + t.name + ''' as TableName, '''
+ c.name + ''' AS ColumnName, '
+ c.name + ' AS Value FROM '
+ t.name + ' WHERE LEN (' + c.name + ') ' + CHAR(62) + ' 25'
FROM sys.columns c
INNER JOIN sys.tables t ON c.object_id = t.object_id
WHERE c.name LIKE '%gl%acc%'
FOR XML PATH('')
), 1, 10, '')
, '>', '>')
EXEC (#sqlstatement)
You may want to add extra filter for columns by their type and max_length:
INNER JOIN sys.types ty ON c.system_type_id = ty.system_type_id
AND (
ty.name IN ('text', 'ntext')
OR (
ty.name IN ('varchar', 'char', 'nvarchar', 'nchar')
AND (c.max_length > 25 OR c.max_length = -1)
)
You will need to create dynamic SQL because you cannot dynamically specify the source table. You could do this using a cursor, or write a select statement that makes a row for each statement you need to run. This shows how to do it with a cursor. You problem looks like an acceptable usage for a cursor:
DECLARE #ColName VARCHAR(MAX);
DECLARE #TableName VARCHAR(MAX);
DECLARE #SomeSQL VARCHAR(MAX);
DECLARE db_cursor CURSOR FOR
SELECT c.name AS ColName, t.name AS TableName
FROM sys.columns c
JOIN sys.tables t ON c.object_id = t.object_id
WHERE c.name LIKE '%gl%acc%'
OPEN db_cursor;
FETCH NEXT FROM db_cursor INTO #ColName, #TableName;
WHILE ##FETCH_STATUS = 0
BEGIN
-- you need to make dynamic SQL
SELECT #SomeSQL = 'SELECT * FROM ' + #TableName + ' WHERE LEN(' + #ColName + ') > 25;'
PRINT(#SomeSQL + CHAR(10));
-- you could execute it directly if you wish.
--EXEC (#SomeSQL);
FETCH NEXT FROM db_cursor INTO #ColName, #TableName;
END
CLOSE db_cursor;
DEALLOCATE db_cursor;
I wasn't sure if you needed to do anything with the results, but this will return the records that meet the criteria you posted in your question
Declare #TableName sysname
Declare #ColName sysname
Declare #dynamic_SQL varchar(MAX)
Declare some_cursor CURSOR FOR
SELECT c.name AS ColName, t.name AS TableName
FROM sys.columns c
JOIN sys.tables t ON c.object_id = t.object_id
WHERE c.name LIKE '%gl%acc%'
OPEN some_cursor
FETCH NEXT FROM some_cursor INTO #ColName, #TableName
WHILE ##FETCH_STATUS = 0
Begin
select #dynamic_SQL = '
Select *
From ' + #TableName + '
Where LEN('+ #ColName +') > 25
'
exec (#dynamic_SQL)
FETCH NEXT FROM some_cursor INTO #ColName, #TableName
End
CLOSE some_cursor
DEALLOCATE some_cursor

How can I easily convert all ntext fields to nvarchar(max) in SQL query?

I would love to be able to write a SQL query, without enumerating the columns, which will return me all the columns, and any ntext column converted to varchar(max). I was wondering if there is a clever way to do this.
This would be great because then I could do the comparison based operators such as UNION, EXCEPT etc. on such queries. The netxt column is not comparable so it fails when using those operators.
My current idea:
Create a function to build the query as dynamic sql. Something similar to this: http://lotsacode.wordpress.com/2010/03/23/sql-server-ntext-cannot-be-selected-as-distinct/
Is there a better way?
Thanks for your input!
NTEXT will be removed from future versions of SQl-Server anyway (along with Image and text), so why not just bite the bullet and change your columns to NVARCHAR(MAX)? It may be costly once, but it will probably be worth it:
ALTER TABLE dbo.T ALTER COLUMN NTextColumn NVARCHAR(MAX) NULL; -- OR NOT NULL
You can generate and execute the script for an entire database using this:
DECLARE #SQL NVARCHAR(MAX) =
( SELECT 'ALTER TABLE ' + QUOTENAME(OBJECT_SCHEMA_NAME(object_id)) + '.' +
QUOTENAME(OBJECT_NAME(object_id)) +
' ALTER COLUMN ' + QUOTENAME(Name) +
' NVARCHAR(MAX) ' +
CASE WHEN is_nullable = 0 THEN 'NOT' ELSE '' END +
' NULL;' + CHAR(13) + 'GO' + CHAR(13)
FROM sys.columns
WHERE system_type_id = 99 --NTEXT
FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)');
EXECUTE sp_executesql #SQL;
I used this cursor (and here, there's no set-based alternative, I'm afraid) to do just that:
DECLARE TableCursor CURSOR FAST_FORWARD
FOR
SELECT
t.Name,
c.name,
c.is_nullable,
typ.user_type_id
FROM
sys.columns c
INNER JOIN
sys.tables t ON c.object_id = t.object_id
INNER JOIN
sys.types typ ON c.system_type_id = typ.system_type_id
WHERE
typ.name IN ('text', 'ntext') -- user_type_id: text = 35, ntext = 99
DECLARE #TableName sysname, #ColumnName sysname, #IsNullable BIT, #TypeID INT
OPEN TableCursor
FETCH NEXT FROM TableCursor INTO #TableName, #ColumnName, #IsNullable, #TypeID
WHILE ##FETCH_STATUS = 0
BEGIN
DECLARE #Stmt NVARCHAR(999)
SET #Stmt = 'ALTER TABLE dbo.[' + #TableName + '] ALTER COLUMN [' + #ColumnName + '] ' +
CASE #TypeID
WHEN 35 THEN ' VARCHAR(MAX) '
WHEN 99 THEN ' NVARCHAR(MAX) '
END +
CASE WHEN #IsNullable = 1 THEN 'NULL' ELSE 'NOT NULL' END
PRINT #Stmt
EXEC (#Stmt)
FETCH NEXT FROM TableCursor INTO #TableName, #ColumnName, #IsNullable, #TypeID
END
CLOSE TableCursor
DEALLOCATE TableCursor
I simplified my code a bit by assuming that all my tables are in the dbo schema - if that's not the case for you, you'd have to include the schema from the sys.schema catalog view, too.
Running this code will turn all text into varchar(max) and all ntext into nvarchar(max) once and for all, and all your issues with text/ntext are gone forever! :-)
Here is my modified version of GarethD's answer above. Had issues with SQL not finding some tables, so I used sys.tables joined with sys.columns. Also, the is_nullable line was incorrect (if the field is not nullable, then you set it to NOT NULL).
DECLARE #SQL NVARCHAR(MAX) = ' ';
SELECT #SQL = #SQL + ' ALTER TABLE ' + QUOTENAME(OBJECT_SCHEMA_NAME(sys.columns.object_id)) + '.' +
QUOTENAME(OBJECT_NAME(sys.columns.object_id)) +
' ALTER COLUMN ' + QUOTENAME(sys.columns.Name) +
' NVARCHAR(MAX) ' +
CASE WHEN is_nullable = 0 THEN 'NOT NULL' ELSE '' END
FROM sys.Tables
inner join sys.columns on sys.tables.object_id = sys.columns.object_id
WHERE sys.columns.system_type_id = 99 ; --NTEXT
EXECUTE sp_executesql #SQL;
GO

List all columns referenced in all procedures of all databases

Is there a way that I can get all the columns and tables referenced in all the stored procedures in all the databases in an instance? The output should be:
Database Procedure Table Column
-------- --------- ----- ------
This will get the list you're after, however it won't help you if you have such column references embedded in dynamic SQL (and may not find references that rely on deferred name resolution). SQL Server doesn't parse the text of the stored procedure to come up with the DMV output.
Try now with COLLATE clauses to deal with cases where you have databases on the same server with different collations.
DECLARE #sql NVARCHAR(MAX) = N'';
SELECT #sql += N'UNION ALL
SELECT
[database] = ''' + REPLACE(name, '''', '''''') + ''',
[procedure] = QUOTENAME(s.name) + ''.'' + QUOTENAME(p.name)
COLLATE Latin1_General_CI_AI,
[table] = QUOTENAME(referenced_schema_name) + ''.''
+ QUOTENAME(referenced_entity_name)
COLLATE Latin1_General_CI_AI,
[column] = QUOTENAME(referenced_minor_name)
COLLATE Latin1_General_CI_AI
FROM ' + QUOTENAME(name) + '.sys.schemas AS s
INNER JOIN ' + QUOTENAME(name) + '.sys.procedures AS p
ON s.[schema_id] = p.[schema_id]
CROSS APPLY ' + QUOTENAME(name)
+ '.sys.dm_sql_referenced_entities'
+ '(QUOTENAME(s.name) + ''.'' + QUOTENAME(p.name), N''OBJECT'') AS d
WHERE d.referenced_minor_id > 0'
FROM sys.databases
WHERE database_id > 4
AND [state] = 0;
SET #sql = STUFF(#sql,1,11,'');
EXEC sp_executesql #sql;
Also the CROSS APPLY syntax won't work if you have databases that are in 80 compatibility mode. Just make sure you don't execute the code in such a database and it should work fine (even if some of the target databases are in 80).
To list all SP Name have contain the specified column name:
SELECT OBJECT_NAME(M.object_id), M.*
FROM sys.sql_modules M
JOIN sys.procedures P
ON M.object_id = P.object_id
WHERE M.definition LIKE '%ColumnName%'
Here is yet another way to do this. This is very DIRTY but I like it. Why? Because I came up with it. Anyway it is using Dynamic SQL inside Dynamic SQL to insert dependency information into temp table that can be queried.
This can be modified into a SP that you can run from time to time to update dependencies information, also temp table can be changes to real table if you want to store it.
IF OBJECT_ID('tempdb.dbo.#SPDependencyDetails') IS NOT NULL
DROP TABLE #SPDependencyDetails
CREATE TABLE #SPDependencyDetails
(
Or_Object_Database NVARCHAR(128)
,Or_Object_Name NVARCHAR(128)
,Ref_Database_Name NVARCHAR(128)
,Ref_Schema_Name NVARCHAR(128)
,Ref_Object_Name NVARCHAR(128)
,Ref_Column_Name NVARCHAR(128)
,Is_Selected BIT
,Is_Updated BIT
,Is_Select_All BIT
,Is_All_Columns_Found BIT
)
DECLARE #database_name VARCHAR(100)
DECLARE database_cursor CURSOR
FOR
SELECT name
FROM sys.databases
WHERE database_id > 4
OPEN database_cursor
FETCH NEXT FROM database_cursor
INTO #database_name
WHILE ##FETCH_STATUS = 0 --Outer Loop begin
BEGIN
DECLARE #WholeLotofSQL NVARCHAR(MAX) = '
DECLARE #object_name VARCHAR(150)
,#sqlstatement NVARCHAR(2500)
DECLARE object_cursor CURSOR --Inner cursor, iterates list of objects that match type
FOR
SELECT name
FROM '+#database_name+'.sys.objects AS o
WHERE o.type = ''P'' --Change Object type to find dependencies of Functions, Views and etc.
ORDER BY 1
OPEN object_cursor
FETCH NEXT FROM object_cursor INTO #object_name
WHILE ##FETCH_STATUS = 0 --Inner Loop Begin
BEGIN
SET #sqlstatement = ''USE '+#database_name+';
INSERT INTO #SPDependencyDetails
SELECT DB_NAME() AS Or_Object_Database
,'''''' + #object_name + '''''' AS Or_Object_Name
,CASE WHEN referenced_database_name IS NULL THEN DB_NAME()
ELSE referenced_database_name
END AS Ref_Database_Name
,referenced_schema_name AS Ref_Schema_Name
,referenced_entity_name AS Ref_Object_Name
,referenced_minor_name AS Ref_Column_Name
,is_selected
,is_updated
,is_select_all
,is_all_columns_found
FROM sys.dm_sql_referenced_entities(''''dbo.'' + #object_name + '''''', ''''OBJECT'''');''
EXEC sys.sp_executesql #sqlstatement
FETCH NEXT FROM object_cursor INTO #object_name
END
CLOSE object_cursor
DEALLOCATE object_cursor'
EXEC sys.sp_executesql #WholeLotofSQL
FETCH NEXT FROM database_cursor INTO #database_name
END
CLOSE database_cursor;
DEALLOCATE database_cursor;
SELECT Or_Object_Database as 'Database'
,Or_Object_Name as 'Procedure'
,Ref_Object_Name as 'Table'
,Ref_Column_Name as 'Column
FROM #SPDependencyDetails

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.

How to find a string inside a entire database?

I have one specific string, such as "123abcd" for example but I don't know the name of the table or even the name of the column inside the table on my SQL Server Database. I want to find it with a select and show all columns of the related string, so I was wondering something like:
select * from Database.dbo.* where * like '%123abcd%'
For obvious reasons it doens't work, but there is a simple way to create a select statement to do something like this?
This will work:
DECLARE #MyValue NVarChar(4000) = 'something';
SELECT S.name SchemaName, T.name TableName
INTO #T
FROM sys.schemas S INNER JOIN
sys.tables T ON S.schema_id = T.schema_id;
WHILE (EXISTS (SELECT * FROM #T)) BEGIN
DECLARE #SQL NVarChar(4000) = 'SELECT * FROM $$TableName WHERE (0 = 1) ';
DECLARE #TableName NVarChar(1000) = (
SELECT TOP 1 SchemaName + '.' + TableName FROM #T
);
SELECT #SQL = REPLACE(#SQL, '$$TableName', #TableName);
DECLARE #Cols NVarChar(4000) = '';
SELECT
#Cols = COALESCE(#Cols + 'OR CONVERT(NVarChar(4000), ', '') + C.name + ') = CONVERT(NVarChar(4000), ''$$MyValue'') '
FROM sys.columns C
WHERE C.object_id = OBJECT_ID(#TableName);
SELECT #Cols = REPLACE(#Cols, '$$MyValue', #MyValue);
SELECT #SQL = #SQL + #Cols;
EXECUTE(#SQL);
DELETE FROM #T
WHERE SchemaName + '.' + TableName = #TableName;
END;
DROP TABLE #T;
A couple caveats, though. First, this is outrageously slow and non-optimized. All values are being converted to nvarchar simply so that they can be compared without error. You may run into problems with values like datetime not converting as expected and therefore not being matched when they should be (false negatives).
The WHERE (0 = 1) is there to make building the OR clause easier. If there are not matches you won't get any rows back.
Here are couple more free tools that can be used for this. Both work as SSMS addins.
ApexSQL Search – 100% free - searches both schema and data in tables. Has couple more useful options such as dependency tracking…
SSMS Tools pack – free for all versions except SQL 2012 – doesn’t look as advanced as previous one but has a lot of other cool features.
I think you have to options:
Build a dynamic SQL using sys.tables and sys.columns to perform the search (example here).
Use any program that have this function. An example of this is SQL Workbench (free).
create procedure usp_find_string(#string as varchar(1000))
as
begin
declare #mincounter as int
declare #maxcounter as int
declare #stmtquery as varchar(1000)
set #stmtquery=''
create table #tmp(tablename varchar(128),columnname varchar(128),rowid int identity)
create table #tablelist(tablename varchar(128),columnname varchar(128))
declare #tmp table(name varchar(128))
declare #tablename as varchar(128)
declare #columnname as varchar(128)
insert into #tmp(tablename,columnname)
select a.name,b.name as columnname from sysobjects a
inner join syscolumns b on a.name=object_name(b.id)
where a.type='u'
and b.xtype in(select xtype from systypes
where name='text' or name='ntext' or name='varchar' or name='nvarchar' or name='char' or name='nchar')
order by a.name
select #maxcounter=max(rowid),#mincounter=min(rowid) from #tmp
while(#mincounter <= #maxcounter )
begin
select #tablename=tablename, #columnname=columnname from #tmp where rowid=#mincounter
set #stmtquery ='select top 1 ' + '[' +#columnname+']' + ' from ' + '['+#tablename+']' + ' where ' + '['+#columnname+']' + ' like ' + '''%' + #string + '%'''
insert into #tmp(name) exec(#stmtquery)
if ##rowcount >0
insert into #tablelist values(#tablename,#columnname)
set #mincounter=#mincounter +1
end
select * from #tablelist
end
In oracle you can use the following sql command to generate the sql commands you need:
select
"select * "
" from "||table_name||
" where "||column_name||" like '%123abcd%' ;" as sql_command
from user_tab_columns
where data_type='VARCHAR2';
Common Resource Grep (crgrep) will search for string matches in tables/columns by name or content and supports a number of DBs, including SQLServer, Oracle and others. Full wild-carding and other useful options.
It's opensource (I'm the author).
http://sourceforge.net/projects/crgrep/
I usually use information_Schema.columns and information_schema.tables, although like #yuck said, sys.tables and sys.columns are shorter to type.
In a loop, concatenate these
#sql = #sql + 'select' + column_name +
' from ' + table_name +
' where ' + column_name ' like ''%''+value+''%' UNION
Then execute the resulting sql.
Here is an easy and convenient cursor based solution
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 name, object_id FROM sys.objects 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)
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