I know it's possible, but I don't know how.
I need to search an SQL Server database for all mentions of a specific string.
For example: I would like to search all tables, views, functions, stored procedures, ... for string "tblEmployes" (not data within the tables).
One of the reasons I need this is I would like to remove some extra data tables that are created, but I am afraid that they are maybe used somewhere in procedures or functions.
This will search every column of every table in a specific database. Create the stored procedure on the database that you want to search in.
The Ten Most Asked SQL Server Questions And Their Answers:
CREATE PROCEDURE FindMyData_String
#DataToFind NVARCHAR(4000),
#ExactMatch BIT = 0
AS
SET NOCOUNT ON
DECLARE #Temp TABLE(RowId INT IDENTITY(1,1), SchemaName sysname, TableName sysname, ColumnName SysName, DataType VARCHAR(100), DataFound BIT)
INSERT INTO #Temp(TableName,SchemaName, ColumnName, DataType)
SELECT C.Table_Name,C.TABLE_SCHEMA, C.Column_Name, C.Data_Type
FROM Information_Schema.Columns AS C
INNER Join Information_Schema.Tables AS T
ON C.Table_Name = T.Table_Name
AND C.TABLE_SCHEMA = T.TABLE_SCHEMA
WHERE Table_Type = 'Base Table'
And Data_Type In ('ntext','text','nvarchar','nchar','varchar','char')
DECLARE #i INT
DECLARE #MAX INT
DECLARE #TableName sysname
DECLARE #ColumnName sysname
DECLARE #SchemaName sysname
DECLARE #SQL NVARCHAR(4000)
DECLARE #PARAMETERS NVARCHAR(4000)
DECLARE #DataExists BIT
DECLARE #SQLTemplate NVARCHAR(4000)
SELECT #SQLTemplate = CASE WHEN #ExactMatch = 1
THEN 'If Exists(Select *
From ReplaceTableName
Where Convert(nVarChar(4000), [ReplaceColumnName])
= ''' + #DataToFind + '''
)
Set #DataExists = 1
Else
Set #DataExists = 0'
ELSE 'If Exists(Select *
From ReplaceTableName
Where Convert(nVarChar(4000), [ReplaceColumnName])
Like ''%' + #DataToFind + '%''
)
Set #DataExists = 1
Else
Set #DataExists = 0'
END,
#PARAMETERS = '#DataExists Bit OUTPUT',
#i = 1
SELECT #i = 1, #MAX = MAX(RowId)
FROM #Temp
WHILE #i <= #MAX
BEGIN
SELECT #SQL = REPLACE(REPLACE(#SQLTemplate, 'ReplaceTableName', QUOTENAME(SchemaName) + '.' + QUOTENAME(TableName)), 'ReplaceColumnName', ColumnName)
FROM #Temp
WHERE RowId = #i
PRINT #SQL
EXEC SP_EXECUTESQL #SQL, #PARAMETERS, #DataExists = #DataExists OUTPUT
IF #DataExists =1
UPDATE #Temp SET DataFound = 1 WHERE RowId = #i
SET #i = #i + 1
END
SELECT SchemaName,TableName, ColumnName
FROM #Temp
WHERE DataFound = 1
GO
To run it, just do this:
exec FindMyData_string 'google', 0
It works amazingly well!!!
If you need to find database objects (e.g. tables, columns, and triggers) by name - have a look at the free Redgate Software tool called SQL Search which does this - it searches your entire database for any kind of string(s).
It's a great must-have tool for any DBA or database developer - did I already mention it's absolutely free to use for any kind of use??
You can also try ApexSQL Search – it’s a free SSMS add-in similar to SQL Search.
If you really want to use only SQL you might want to try this script:
select
S.name as [Schema],
o.name as [Object],
o.type_desc as [Object_Type],
C.text as [Object_Definition]
from sys.all_objects O inner join sys.schemas S on O.schema_id = S.schema_id
inner join sys.syscomments C on O.object_id = C.id
where S.schema_id not in (3,4) -- avoid searching in sys and INFORMATION_SCHEMA schemas
and C.text like '%ICE_%'
order by [Schema]
You can export your database (if small) to your hard drive / desktop, and then just do a string search via a text search program or text editor.
For getting a table by name in SQL Server:
SELECT *
FROM sys.Tables
WHERE name LIKE '%Employees%'
For finding a stored procedure by name:
SELECT name
FROM sys.objects
WHERE name = 'spName'
To get all stored procedures related to a table:
----Option 1
SELECT DISTINCT so.name
FROM syscomments sc
INNER JOIN sysobjects so ON sc.id=so.id
WHERE sc.TEXT LIKE '%tablename%'
----Option 2
SELECT DISTINCT o.name, o.xtype
FROM syscomments c
INNER JOIN sysobjects o ON c.id=o.id
WHERE c.TEXT LIKE '%tablename%'
This code searching procedure and function but not search in table :)
SELECT name
FROM sys.all_objects
WHERE Object_definition(object_id)
LIKE '%text%'
ORDER BY name
You could;
Script the database to a single file and search the file for tblEmployees using a text editor. In SQL Server Management Studio (SSMS), right click over the database and choose Generate Scripts.
Use SSMS 'View Dependencies' by right clicking over tblEmployees to see which other objects are dependent on it
Use a free third-party tool such as Redgate Software's SQL Search to search all database objects by name and content by keyword.
My version...
I named it "Needle in the haystack" for obvious reasons.
It searches for a specific value in each row and each column, not for column names, etc.
Execute search (replace values for the first two variables of course):
DECLARE #SEARCH_DB VARCHAR(100)='REPLACE_WITH_YOUR_DB_NAME'
DECLARE #SEARCH_VALUE_LIKE NVARCHAR(100)=N'%REPLACE_WITH_SEARCH_STRING%'
SET NOCOUNT ON;
DECLARE col_cur CURSOR FOR
SELECT TABLE_CATALOG, TABLE_SCHEMA, TABLE_NAME, COLUMN_NAME, DATA_TYPE
FROM information_schema.columns WHERE TABLE_CATALOG=#SEARCH_DB AND DATA_TYPE NOT IN ('timestamp', 'datetime');
DECLARE #TOTAL int = (SELECT COUNT(*)
FROM information_schema.columns WHERE TABLE_CATALOG=#SEARCH_DB AND DATA_TYPE NOT IN ('timestamp', 'datetime'));
DECLARE #TABLE_CATALOG nvarchar(500), #TABLE_SCHEMA nvarchar(500), #TABLE_NAME nvarchar(500), #COLUMN_NAME nvarchar(500), #DATA_TYPE nvarchar(500);
DECLARE #SQL nvarchar(4000)='';
PRINT '-------- BEGIN SEARCH --------';
OPEN col_cur;
FETCH NEXT FROM col_cur INTO #TABLE_CATALOG, #TABLE_SCHEMA, #TABLE_NAME, #COLUMN_NAME, #DATA_TYPE;
BEGIN TRY DROP TABLE ##RESULTS; END TRY BEGIN CATCH END CATCH
CREATE TABLE ##RESULTS( TABLE_CATALOG nvarchar(500), TABLE_SCHEMA nvarchar(500), TABLE_NAME nvarchar(500), COLUMN_NAME nvarchar(500), DATA_TYPE nvarchar(500), RECORDS int)
DECLARE #SHOULD_CAST bit=0
DECLARE #i int =0
DECLARE #progress_sum bigint=0
WHILE ##FETCH_STATUS = 0
BEGIN
-- PRINT '' + CAST(#i as varchar(100)) +' of ' + CAST(#TOTAL as varchar(100)) + ' ' + #TABLE_CATALOG+'.'+#TABLE_SCHEMA+'.'+#TABLE_NAME+': '+#COLUMN_NAME+' ('+#DATA_TYPE+')';
SET #SHOULD_CAST = (SELECT CASE #DATA_TYPE
WHEN 'varchar' THEN 0
WHEN 'nvarchar' THEN 0
WHEN 'char' THEN 0
ELSE 1 END)
SET #SQL='SELECT '''+#TABLE_CATALOG+''' catalog_name, '''+#TABLE_SCHEMA+''' schema_name, '''+#TABLE_NAME+''' table_name, '''+#COLUMN_NAME+''' column_name, '''+#DATA_TYPE+''' data_type, ' +
+' COUNT(['+#COLUMN_NAME+']) records '+
+' FROM '+#TABLE_CATALOG+'.'+#TABLE_SCHEMA+'.'+#TABLE_NAME +
+' WHERE ' + CASE WHEN #SHOULD_CAST=1 THEN 'CAST(['+#COLUMN_NAME + '] as NVARCHAR(max)) ' ELSE ' ['+#COLUMN_NAME + '] ' END
+' LIKE '''+ #SEARCH_VALUE_LIKE + ''' '
-- PRINT #SQL;
IF #i % 100 = 0
BEGIN
SET #progress_sum = (SELECT SUM(RECORDS) FROM ##RESULTS)
PRINT CAST (#i as varchar(100)) +' of ' + CAST(#TOTAL as varchar(100)) +': '+ CAST (#progress_sum as varchar(100))
END
INSERT INTO ##RESULTS (TABLE_CATALOG, TABLE_SCHEMA, TABLE_NAME, COLUMN_NAME, DATA_TYPE, RECORDS)
EXEC(#SQL)
FETCH NEXT FROM col_cur INTO #TABLE_CATALOG, #TABLE_SCHEMA, #TABLE_NAME, #COLUMN_NAME, #DATA_TYPE;
SET #i=#i+1
-- IF #i > 1000
-- BREAK
END
CLOSE col_cur;
DEALLOCATE col_cur;
SELECT * FROM ##RESULTS WHERE RECORDS>0;
Then to view results, even while executing, from another window, execute:
DECLARE #SEARCH_VALUE_LIKE NVARCHAR(100)=N'%#FLEX#%'
SELECT * FROM ##RESULTS WHERE RECORDS>0;
SET NOCOUNT ON;
DECLARE col_cur CURSOR FOR
SELECT TABLE_CATALOG, TABLE_SCHEMA, TABLE_NAME, COLUMN_NAME, DATA_TYPE
FROM ##RESULTS WHERE RECORDS>0;
DECLARE #TABLE_CATALOG nvarchar(500), #TABLE_SCHEMA nvarchar(500), #TABLE_NAME nvarchar(500), #COLUMN_NAME nvarchar(500), #DATA_TYPE nvarchar(500);
DECLARE #SQL nvarchar(4000)='';
OPEN col_cur;
FETCH NEXT FROM col_cur INTO #TABLE_CATALOG, #TABLE_SCHEMA, #TABLE_NAME, #COLUMN_NAME, #DATA_TYPE;
DECLARE #i int =0
DECLARE #SHOULD_CAST bit=0
WHILE ##FETCH_STATUS = 0
BEGIN
SET #SHOULD_CAST = (SELECT CASE #DATA_TYPE
WHEN 'varchar' THEN 0
WHEN 'nvarchar' THEN 0
WHEN 'char' THEN 0
ELSE 1 END)
SET #SQL='SELECT '''+#TABLE_CATALOG+''' catalog_name, '''+#TABLE_SCHEMA+''' schema_name, '''+#TABLE_NAME+''' table_name, '''+#COLUMN_NAME+''' column_name, '''+#DATA_TYPE+''' data_type, ' +
+' ['+#COLUMN_NAME+']'+
+', * '
+' FROM '+#TABLE_CATALOG+'.'+#TABLE_SCHEMA+'.'+#TABLE_NAME +
+' WHERE ' + CASE WHEN #SHOULD_CAST=1 THEN 'CAST(['+#COLUMN_NAME + '] as NVARCHAR(max)) ' ELSE ' ['+#COLUMN_NAME + '] ' END
+' LIKE '''+ #SEARCH_VALUE_LIKE + ''' '
PRINT #SQL;
EXEC(#SQL)
FETCH NEXT FROM col_cur INTO #TABLE_CATALOG, #TABLE_SCHEMA, #TABLE_NAME, #COLUMN_NAME, #DATA_TYPE;
SET #i=#i+1
-- IF #i > 10
-- BREAK
END
CLOSE col_cur;
DEALLOCATE col_cur;
Few mentions about it:
it uses cursors instead of a blocking while loop
it can print progress (uncomment if needed)
it can exit after a few attempts (uncomment the IF at the end)
it displays all records
you can fine tune it as needed
DISCLAIMERS:
DO NOT run it in production environments!
It is slow. If the DB is accessed by other services/users, please add " WITH (NOLOCK) " after every table name in all the selects, especially the dynamic select ones.
It does not validate/protect against all sorts of SQL injection options.
If your DB is huge, prepare yourself for some sleep, make sure the query will not be killed after a few minutes.
It casts some values to string, including ints/bigints/smallints/tinyints. If you don't need those, put them at the same exclusion lists with the timestamps at the top of the script.
The content of all stored procedures, views and functions are stored in field text of table sysComments. The name of all objects are stored in table sysObjects and the columns are in sysColumns.
Having this information, you can use this code to search in content of views, stored procedures, and functions for the specified word:
Select b.name from syscomments a
inner join sysobjects b on a.id = b.id
where text like '%tblEmployes%'
This query will give you the objects which contains the word "tblEmployes" .
To search by the name of Objects you can use this code:
Select name from sysobjects
where name like '%tblEmployes%'
And finally to find the objects having at least one column containing the word "tblEmployes", you can use this code:
Select b.name from syscolumns a inner join sysobjects b on a.id = b.id
where a.name like '%tblEmployes%'
You can combine these three queries with union:
Select distinct b.name from syscomments a
inner join sysobjects b on a.id = b.id
where text like '%tblEmployes%'
union
Select distinct name from sysobjects
where name like '%tblEmployes%'
union
Select distinct b.name from syscolumns a inner join sysobjects b on a.id = b.id
where a.name like '%tblEmployes%'
With this query you have all objects containing the word "tblEmployes" in content or name or as a column.
I was given access to a database, but not the table where my query was being stored in.
Inspired by #marc_s answer, I had a look at HeidiSQL which is a Windows program that can deal with MySQL, SQL Server, and PostgreSQL.
I found that it can also search a database for a string.
It will search each table and give you how many times it found the string per table!
This will search for a string over every database:
declare #search_term varchar(max)
set #search_term = 'something'
select #search_term = 'use ? SET QUOTED_IDENTIFIER ON
select
''[''+db_name()+''].[''+c.name+''].[''+b.name+'']'' as [object],
b.type_desc as [type],
d.obj_def.value(''.'',''varchar(max)'') as [definition]
from (
select distinct
a.id
from sys.syscomments a
where a.[text] like ''%'+#search_term+'%''
) a
inner join sys.all_objects b
on b.[object_id] = a.id
inner join sys.schemas c
on c.[schema_id] = b.[schema_id]
cross apply (
select
[text()] = a1.[text]
from sys.syscomments a1
where a1.id = a.id
order by a1.colid
for xml path(''''), type
) d(obj_def)
where c.schema_id not in (3,4) -- avoid searching in sys and INFORMATION_SCHEMA schemas
and db_id() not in (1,2,3,4) -- avoid sys databases'
if object_id('tempdb..#textsearch') is not null drop table #textsearch
create table #textsearch
(
[object] varchar(300),
[type] varchar(300),
[definition] varchar(max)
)
insert #textsearch
exec sp_MSforeachdb #search_term
select *
from #textsearch
order by [object]
If I want to find where anything I want to search is, I use this:
DECLARE #search_string varchar(200)
SET #search_string = '%myString%'
SELECT DISTINCT
o.name AS Object_Name,
o.type_desc,
m.definition
FROM sys.sql_modules m
INNER JOIN
sys.objects o
ON m.object_id = o.object_id
WHERE m.definition Like #search_string;
It's easy to search a string in your database with phpmyadmin. There you can chose from many search options and you can see where your search phrase is mentioned.
Here is the same script as submitted by user l--''''''---------'''''''''''', but corrected to work on a case-sensitive SQL instance, and with some other minor improvements.
DROP PROCEDURE IF EXISTS dbo.spFind_Text_In_Database
GO
CREATE PROCEDURE dbo.spFind_Text_In_Database
#strText_To_Find NVARCHAR(4000),
#bitExact_Match BIT = 0
AS
SET NOCOUNT ON
DECLARE #Temp TABLE(RowId INT IDENTITY(1,1), SchemaName sysname, TableName sysname, ColumnName SysName, DataType VARCHAR(100), DataFound BIT)
INSERT INTO #Temp(TableName,SchemaName, ColumnName, DataType)
SELECT C.TABLE_NAME, C.TABLE_SCHEMA, C.COLUMN_NAME, C.DATA_TYPE
FROM INFORMATION_SCHEMA.COLUMNS AS C
INNER Join INFORMATION_SCHEMA.TABLES AS T
ON C.TABLE_NAME = T.TABLE_NAME
AND C.TABLE_SCHEMA = T.TABLE_SCHEMA
WHERE TABLE_TYPE = 'BASE TABLE'
And DATA_TYPE In ('ntext','text','nvarchar','nchar','varchar','char')
DECLARE #i INT
DECLARE #MAX INT
DECLARE #TableName sysname
DECLARE #ColumnName sysname
DECLARE #SchemaName sysname
DECLARE #SQL NVARCHAR(4000)
DECLARE #PARAMETERS NVARCHAR(4000)
DECLARE #DataExists BIT
DECLARE #SQLTemplate NVARCHAR(4000)
SELECT #SQLTemplate = CASE WHEN #bitExact_Match = 1
THEN 'If Exists(Select *
From ReplaceTableName
Where Convert(nVarChar(4000), [ReplaceColumnName])
= ''' + #strText_To_Find + '''
)
Set #DataExists = 1
Else
Set #DataExists = 0'
ELSE 'If Exists(Select *
From ReplaceTableName
Where Convert(nVarChar(4000), [ReplaceColumnName])
Like ''%' + #strText_To_Find + '%''
)
Set #DataExists = 1
Else
Set #DataExists = 0'
END,
#PARAMETERS = '#DataExists Bit OUTPUT',
#i = 1
SELECT #i = 1, #MAX = MAX(RowId)
FROM #Temp
WHILE #i <= #MAX
BEGIN
SELECT #SQL = REPLACE(REPLACE(#SQLTemplate, 'ReplaceTableName', QUOTENAME(SchemaName) + '.' + QUOTENAME(TableName)), 'ReplaceColumnName', ColumnName)
FROM #Temp
WHERE RowId = #i
PRINT #SQL
EXEC sp_executesql #SQL, #PARAMETERS, #DataExists = #DataExists OUTPUT
IF #DataExists =1
UPDATE #Temp SET DataFound = 1 WHERE RowId = #i
SET #i = #i + 1
END
SELECT SchemaName,TableName, ColumnName
FROM #Temp
WHERE DataFound = 1
GO
Searching SQL Database objects is possible with SQL Server Management Studio (SSMS) with the following methods, with SSMS Object Search: object explorer details or T-SQL scripts as explained in following:
Different ways to search for SQL Server database objects
SQL Server Find Anything in Object Explorer in SSMS
Search text with wildcards
Here is how you can search the database in Swift using the FMDB library.
First, go to this link and add this to your project: FMDB. When you have done that, then here is how you do it. For example, you have a table called Person, and you have firstName and secondName and you want to find data by first name, here is a code for that:
func loadDataByfirstName(firstName : String, completion: #escaping CompletionHandler){
if isDatabaseOpened {
let query = "select * from Person where firstName like '\(firstName)'"
do {
let results = try database.executeQuery(query, values: [firstName])
while results.next() {
let firstName = results.string(forColumn: "firstName") ?? ""
let lastName = results.string(forColumn: "lastName") ?? ""
let newPerson = Person(firstName: firstName, lastName: lastName)
self.persons.append(newPerson)
}
completion(true)
}catch let err {
completion(false)
print(err.localizedDescription)
}
database.close()
}
}
Then in your ViewController you will write this to find the person detail you are looking for:
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
SQLManager.instance.openDatabase { (success) in
if success {
SQLManager.instance.loadDataByfirstName(firstName: "Hardi") { (success) in
if success {
// You have your data Here
}
}
}
}
}
I am currently asked to validate the result of a global search which to find all records containing some keywords cross whole database. To do so, I need to check all the rows in each table that have keywords. The result for this global search is ready and partially of the result looks like the one below:
table_name
column_name
keyword
cnt
Wf_Process
Name_EN
FEC
11
Wf_Process
FTABLENAME
GB
14
ICCClass
Name_EN
GB
4
What I am trying to do is using the 'like' operator to extract all the data in each table where columns containing keywords. That is, I will use query such as:
select distinct Name_EN, FTABLENAME from Wf_Process where Name_EN like '%FEC%' or FTABLENAME like '%GB%'
and
select distinct Name_EN from ICCClass where Name_EN like '%GB%'
to pull out all data I need in whole database. If I only have three records, then it is not a problem. However my result returned over thousands tables have more than 10K rows containing keywords in total. Therefore, I was trying to use a loop to do this mission but I failed.
My question therefore is, does anyone have any idea to write a loop to do the 'like' search for all the tables in one time? Or is there another way rather than loop can do this in SQL Server?
Thank you very much!
You need dynamic SQL for this. You can generate a big UNION ALL query of all the tables together.
DECLARE #sql nvarchar(max) = (
SELECT STRING_AGG(CAST('
SELECT
' + QUOTENAME(con.table_name, '''') + ' table_name,
' + QUOTENAME(con.column_name, '''') + ' column_name,
' + QUOTENAME(con.keyword, '''') + ' keyword,
COUNT(*) cnt
FROM ' + QUOTENAME(s.name) + '.' + QUOTENAME(t.name) + ' t
WHERE t.' + QUOTENAME(c.name) + ' LIKE ' + QUOTENAME('%' + con.keyword + '%', '''')
AS nvarchar(max)), '
UNION ALL')
FROM YourConditions con
JOIN sys.tables t ON t.table_name
JOIN sys.schemas s ON s.schema_id = t.schema_id
JOIN sys.columns c ON c.object_id = t.object_id
WHERE t.name = con.table_name
AND c.name = con.column_name
);
PRINT #sql; -- your friend
EXEC sp_executesql #sql;
There are more efficient ways to do this if there are many columns or keywords per table, but this should get you started.
The question looks odd, thou can be done via dynamic sql, but not as a regular solution more like a one off or POC/test.
use tempdb
GO
drop table if exists search_result
go
create table search_result (
table_name sysname
,column_name sysname
,keyword varchar(100))
go
insert into search_result values
('Wf_Process', 'Name_EN', 'FEC')
,('Wf_Process' , 'FTABLENAME', 'GB')
,('ICCClass', 'Name_EN', 'GB')
GO
drop table if exists result
create table result (val varchar(500))
go
declare #col sysname
declare #tab sysname
declare #kw varchar(100)
declare #sql varchar(1000)
while exists (select * from search_result)
begin
select top 1
#tab = table_name
, #col = column_name
, #kw = keyword
from search_result
set #sql = concat('insert into result select ', #col, ' from ', #tab, ' where ', #col, ' like ''%', #kw, '%''' )
print(#sql)
exec (#sql)
delete from search_result
where table_name = #tab and column_name = #col and keyword = #kw
end
GO
select * from result
--initially trying to get all the column name with its respective table name, finding out if there is that particular keyword in all table,
--if yes, insert into temp table, if there aint keyword, it will insert the record too but the count of record will be zero.
--trying to make it dynamic and running it inside the loop by assigning row number to each table with different column.
IF OBJECT_ID('tempdb..#TEMP') IS NOT NULL
DROP TABLE #TEMP
CREATE TABLE #TEMP (TABLE_NAME NVARCHAR(200), COLUMN_NAME NVARCHAR(200), KEYWORD NVARCHAR(200), CNT INT)
DECLARE #TABLE NVARCHAR(200)
DECLARE #TABLE_ID INT
SET #TABLE_ID = 1
DECLARE #TABLE_NAME NVARCHAR (200)
DECLARE #FOR_LOOP INT
DECLARE #COLUMN NVARCHAR(200)
DECLARE #COLUMN_NAME NVARCHAR(200)
--TOTAL NO OF RECORDS FOR LOOP
SET #FOR_LOOP = (SELECT COUNT(*)
FROM SYS.tables T
JOIN SYS.all_columns C ON T.object_id = C.object_id
JOIN INFORMATION_SCHEMA.TABLES S ON S.TABLE_NAME = T.name)
DECLARE #STRINGS NVARCHAR(200)
SET #STRINGS = '%FEC%' --------->ENTER YOUR KEYWORD HERE, TRY ONE AT A TIME
DECLARE #COUNT INT
WHILE #TABLE_ID <= #FOR_LOOP
BEGIN
SET #TABLE = (SELECT CAST(TABLE_NAME AS NVARCHAR(200))
FROM
(SELECT ROW_NUMBER()OVER(ORDER BY T.NAME) TABLE_ID
,S.TABLE_SCHEMA SCHEMA_NAME ,T.NAME TABLE_NAME, C.name COLUMN_NAME
FROM SYS.tables T
JOIN SYS.all_columns C ON T.object_id = C.object_id
JOIN INFORMATION_SCHEMA.TABLES S ON S.TABLE_NAME = T.name)A
WHERE TABLE_ID = #TABLE_ID)
SET #TABLE_NAME = '['+#TABLE+']'
SET #COLUMN = (SELECT CAST(COLUMN_NAME AS NVARCHAR(200))
FROM
(SELECT ROW_NUMBER()OVER(ORDER BY T.NAME) TABLE_ID
,S.TABLE_SCHEMA SCHEMA_NAME ,T.NAME TABLE_NAME, C.name COLUMN_NAME
FROM SYS.tables T
JOIN SYS.all_columns C ON T.object_id = C.object_id
JOIN INFORMATION_SCHEMA.TABLES S ON S.TABLE_NAME = T.name)A
WHERE TABLE_ID = #TABLE_ID)
SET #COLUMN_NAME = '['+#COLUMN+']'
DECLARE #EXEC NVARCHAR(200) = 'SELECT ' + #COLUMN_NAME +' FROM ' + #TABLE_NAME + ' WHERE ' + #COLUMN_NAME + ' LIKE ' + ''''+#STRINGS+''''
--THERE MUST BE ANOTHER WAY TO REPLACE SP_EXECUTESQL FOR BETTER PERFORMANCE, AS IT WILL BE EXECUTED AS MANY TIMES AS THERE ARE RECORDS IN #FOR_LOOP
EXEC SP_EXECUTESQL #EXEC
SET #COUNT = (SELECT ##ROWCOUNT)
IF (SELECT ##ROWCOUNT) >=1
BEGIN
INSERT INTO #TEMP VALUES
(#TABLE_NAME, #COLUMN_NAME, #STRINGS, #COUNT)
SET #TABLE_ID = #TABLE_ID + 1
END
ELSE
--DONT KNOW WHY THIS ELSE PART IS NOT TOUCHED, WHEREAS I THINK IT SHOULD HAVE
BEGIN
PRINT 'RECORD NOT FOUND'
END
END
GO
--AFTER THE ABOVE BLOCK IS EXECUTED THEN TRY RUNNING BELOW ONE
SELECT *FROM #TEMP WHERE CNT>0
--THERE MAY BE MULTIPLE ERROS, MUST BE EDITED AND CAN MAKE IT AS A PROCEDURE TOO.
I have a SQL database with 60+ tables, almost all of which are populated with a CLIENTID field. I want to count the number of unique client IDs in each table.
The results I'm looking for are:
TABLE_NAME; CLIENTID_COUNT
dbo.HISTORY; 650
dbo.VISITS; 596
dbo.SALES; 1053
...; ...
This seems like it should be so simple but I've been playing around with cursors for hours and can't figure this one out. Please help!
IF OBJECT_ID('tempdb..#temp_RESULTS') IS NOT NULL DROP TABLE #temp_RESULTS
CREATE TABLE #TEMP_RESULTS
(
TABLENAME VARCHAR(MAX),
CLIENTCNT BIGINT
)
DECLARE #TABLENAME VARCHAR(MAX)
DECLARE #command VARCHAR(MAX)
IF OBJECT_ID('tempdb..#temp_PROCESS') IS NOT NULL DROP TABLE #temp_PROCESS
SELECT * INTO #TEMP_PROCESS FROM sys.tables
WHILE EXISTS(SELECT * FROM [#TEMP_PROCESS])
BEGIN
SET #TABLENAME = (SELECT TOP 1 [NAME] FROM [#TEMP_PROCESS])
SET #command = ('SELECT ''' + #TABLENAME + ''', COUNT(DISTINCT CLIENTID) AS CLIENTCNT FROM ' + #TABLENAME)
SELECT #command
INSERT INTO #TEMP_RESULTS
EXEC(#command)
DELETE FROM [#TEMP_PROCESS] WHERE [NAME] = #TABLENAME
END
SELECT * FROM [#TEMP_RESULTS]
Assuming the column is exactly ClientId in every table, you should be able to use this as is:
DROP TABLE IF EXISTS #clientId
CREATE TABLE #clientId
(
TableName nvarchar(1000),
ClientIdCount bigint
)
DECLARE #TableName nvarchar(1000);
DECLARE #CurrentQuery nvarchar(2000);
DECLARE result_cursor CURSOR local fast_forward FOR
SELECT DISTINCT
'['+TABLE_SCHEMA + '].[' + TABLE_NAME + ']'
FROM
INFORMATION_SCHEMA.COLUMNS
WHERE
COLUMN_NAME = 'ClientId'
OPEN result_cursor
FETCH NEXT FROM result_cursor into #TableName
WHILE ##FETCH_STATUS = 0
BEGIN
SET #CurrentQuery = 'SELECT ''' + #TableName + ''', COUNT(DISTINCT ClientId) FROM ' + #TableName
--print #CurrentQuery
INSERT INTO
#clientId
(
TableName,
ClientIdCount
)
EXEC(#CurrentQuery)
FETCH NEXT FROM result_cursor into #TableName
END
--end loop
--clean up
CLOSE result_cursor
DEALLOCATE result_cursor
GO
SELECT
*
FROM
#clientId
You could use dynamic sql.
This will read through your system tables, find those that have a ClientID column, and build the text of a query that's in the general shape of 'Select Count(DISTINCT ClientID)' from each table.
DECLARE #SQLQuery as nvarchar(max) = ''
------------------------------------
-- GET THE TABLES THAT HAVE A CLIENTID FROM SCHEMA
SELECT #SQLQuery = #SQLQuery + qryTxt FROM (
SELECT DISTINCT 'SELECT ''' + tables.name + ''', COUNT(DISTINCT CLIENTID) FROM ' + tables.name + ' UNION ' AS qryTxt
FROM sys.columns left join sys.tables on columns.object_id = tables.object_id where columns.name = CLIENTID AND isnull(tables.name, '') <> '') subquery
------------------------------------
-- REMOVE THE LAST 'UNION' KEYWORD FROM SQLQUERY
SET #SQLQuery = left(#sqlQuery, len(#sqlQuery) - 5)
------------------------------------
-- EXECUTE
execute sp_executesql #SQLQuery
I really dislike cursors and loops. Even though this is not going to be much difference for a performance perspective I like to share how you can leverage the system tables and dynamic sql to avoid using a cursor, while loop or temp tables for something like this.
This code is literally all you need to to do this.
declare #SQL nvarchar(max) = ''
select #SQL = #SQL + 'select TableName = ''' + t.name + ''', ClientID_Count = count(distinct clientID)
from ' + QUOTENAME(t.name) + ' UNION ALL '
from sys.tables t
join sys.columns c on c.object_id = t.object_id
where c.name = 'clientID'
select #SQL = left(#SQL, len(#SQL) - 10) --removes the last UNION ALL
select #SQL
--once your comfortable the dynamic sql is correct just uncomment the line below.
--exec sp_executesql #SQL
A similar pattern to other answers here, but this is how I would tackle it:
IF OBJECT_ID('#Tables', 'U') IS NOT NULL
DROP TABLE #Tables;
SELECT ID = IDENTITY(INT, 1, 1),
SchemaName = OBJECT_SCHEMA_NAME([object_id]),
TableName = OBJECT_NAME([object_id]),
ColumnName = name,
DistinctCount = 0
INTO #Tables
FROM sys.columns
WHERE name = 'CLIENTID';
DECLARE #ID INT = 1,
#MaxID INT = (SELECT MAX(ID) FROM #Tables);
WHILE #ID < #MaxID
BEGIN;
DECLARE #SQLCommand VARCHAR(MAX);
SELECT #SQLCommand = FORMATMESSAGE('
UPDATE #Tables SET DistinctCount = (
SELECT COUNT(DISTINCT %s) FROM %s.%s
)
WHERE ID = %i;',
QUOTENAME(ColumnName), QUOTENAME(SchemaName), QUOTENAME(TableName), ID)
FROM #Tables
WHERE ID = #ID;
EXEC (#SQLCommand);
SET #ID += 1;
END;
SELECT *
FROM #Tables;
I have a select statement I want to make. I want to select
SELECT COLUMN_NAME AS FieldName FROM
INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = 'table1'
However I want to create another column named Value which is a particular row in table1
so I have rows of the column name and the corresponding single value. Any thoughts on how to approach this?
The following query produces a value (the minimum) for each column:
SELECT '''select '+COLUMN_NAME+''' AS FieldName, (select cast(MIN('+COLUMN_NAME+') as varchar(8000)) from '+const.tablename+')'
FROM INFORMATION_SCHEMA.COLUMNS c cross join
(select 'AllCurveNames' as tablename) const
WHERE c.TABLE_NAME = const.tablename
However, this produces a separate query for each row. To combine them together, you need a string aggregate concatenation. This is how you would do it in SQL Server:
declare #sql varchar(max);
SELECT #sql = (select 'select '''+COLUMN_NAME+''' AS FieldName, (select cast(MIN('+COLUMN_NAME+') as varchar(8000)) from '+const.tablename + ') union all '
FROM INFORMATION_SCHEMA.COLUMNS c cross join
(select WHATEVER as tablename) const
WHERE c.TABLE_NAME = const.tablename
for xml path('')
);
select #sql = LEFT(#sql, len(#sql) - 9);
exec(#sql);
Use a cross join, which is implicit if you just select from two tables with no join (i.e., from t1, t2):
SELECT COLUMN_NAME AS FieldName,
Table1.MyField
FROM
INFORMATION_SCHEMA.COLUMNS, Table1
WHERE
TABLE_NAME = 'table1'
AND
MyTable.ID = 123
I actually came up with a bit of a crazy solution but it works:
declare #tbl_name as varchar(255)
declare #field as varchar(255)
declare #val as varchar(255)
declare #SQL as nvarchar(4000)
create table #tbl ( [FieldName][varchar](255), [FieldVal][varchar](255))
set #tbl_name = 'table1'
DECLARE mah_cursor CURSOR FAST_FORWARD
FOR
SELECT COLUMN_NAME FROM
INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = #tbl_name
OPEN mah_cursor
FETCH NEXT FROM mah_cursor INTO #field
WHILE ##FETCH_STATUS = 0
BEGIN
set #SQL = 'set #val = (Select top 1 ' + #field + ' from ' + #tbl_name + ')'
print #SQL
exec sp_executesql #query = #SQL, #params = N'#val varchar(255) OUTPUT', #val = #val OUTPUT
insert into #tbl ([FieldName],[FieldVal] ) values (#field, #val)
FETCH NEXT FROM mah_cursor INTO #field
END
CLOSE mah_cursor
DEALLOCATE mah_cursor
select * from #tbl
drop table #tbl
It loops through each value and adds it. The Fast_Forward feature optimizes the query for high performance
Environment: SQL Server 2005/2008,
pubs database
I have inserted into a table variable a set of data as shown below using information_schema tables.
Now I would like to update the flag column based on the result of executing the query in the column dSQL. I was able to update using loops/cursor and then used sp_executeSQL to
update the column and then update flag column later. But is there an alternate set-based way to do this without looping through all individual rows?
use pubs
go
declare #dsql Nvarchar(max)='', #tablename varchar(100), #colname varchar(100)
declare #t table (
TABLE_NAME varchar(100),
COLUMN_NAME varchar(100)
)
insert into #t
select distinct t.TABLE_NAME, c.COLUMN_NAME
from information_Schema.tables t
inner join
information_Schema.columns c
on t.TABLE_CATALOG = c.TABLE_CATALOG
where t.TABLE_SCHEMA = c.TABLE_SCHEMA
and t.TABLE_TYPE = 'BASE TABLE'
and c.DATA_TYPE = 'varchar'
select *, Dsql = 'select ' + COLUMN_NAME + ' from ' + TABLE_NAME + ' WHERE '
+ COLUMN_NAME + ' = ''Menlo Park''', '' as Flag
FROM #t
GO
I had an idea to create a function and call the function for each row to execute individual query statement but calling the function for each record might be a performance hit.
It's a loop or a function as you suggested (which is really a loop anyway).
Not possible, I made a script like it earlier.
declare #searchvalue varchar(100)
set nocount off
set #searchvalue = 'Hello world'
create table #tt (table_name varchar(64), column_name varchar(64), count int)
select * into #t from
(
select 'select ''' + a.table_name + ''' ''table_name'',''' + a.column_name + ''' ''column_name'', count(*) count from [' + a.table_name +'] where [' +a.column_name+']='''+#searchvalue +'''' + ' group by ['+ a.column_name+']' sqlstring
from INFORMATION_SCHEMA.COLUMNS a
join
INFORMATION_SCHEMA.TABLES b
on a.table_name = b.table_name
and b.table_type = 'base table'
where data_type = 'varchar'
) a
--loop cursor
Declare #sqlstring as nvarchar(500)
Declare SqlCursor CURSOR FAST_FORWARD FOR
SELECT sqlstring FROM #t
OPEN SqlCursor
FETCH NEXT FROM SqlCursor
INTO #sqlstring
WHILE ##FETCH_STATUS = 0
BEGIN
insert #tt
exec(#sqlstring)
FETCH NEXT FROM SqlCursor
INTO #sqlstring
END
CLOSE SqlCursor
DEALLOCATE SqlCursor
select * from #tt
drop table #tt
drop table #t
Use what you want
This is an old question, but I'd like to add a different answer all the same.
Try the following script (no cursor, no loop (according to execution plan)): (tested in MS SQL 2012)
-- Setting up test data/code
SELECT N'SELECT * FROM INFORMATION_SCHEMA.COLUMNS AS C' T
INTO #Code
UNION ALL
SELECT N'SELECT * FROM INFORMATION_SCHEMA.TABLES AS T'
-- Variable to hold the selected queries, seperated by CrLf. You can also add a "GO" or ";"
DECLARE #SQL NVARCHAR(MAX) = CHAR(13) + CHAR(10)
-- Concatenate the selected queries together into the variable
SELECT #SQL = #SQL + CHAR(13) + CHAR(10) + C.T
FROM #Code AS C
-- Execute
EXEC sys.sp_executesql #SQL
-- Clean up
DROP TABLE #Code