EDIT: Oops, didn't realize at first you were working with mssql and not mysql. The principle below will still work; you'll just need to adjust the syntax a bit and use a user-function to replace group_concat since mssql doesn't have that.
Here's an approach without sp_MSForeachdb
. Note that you will want to sanitize the parameters first.
delimiter $$
create procedure FindDatabases
(
in varName varchar(2000),
in tableName varchar(2000),
in columnName varchar(2000)
)
begin
declare selectQuery varchar(2000);
select group_concat(
concat('select ''',
table_schema,
''' as DatabaseName from ',
table_schema,
'.',
tableName,
' where ',
columnName,
' = ''',
varName,
'''')
separator ' union ') as DatabaseNames
from information_schema.tables
where table_name = tableName
into @selectQuery;
prepare preparedSql from @selectQuery;
execute preparedSql;
deallocate prepare preparedSql;
end $$
delimiter ;
Example usage:
call FindDatabases ( 'variable', 'Items', 'ColumnName' )
This procedure generates a sql query for each database with a table name matching the table name supplied, unions them together, and then executes them. Each query in the union returns its database name if the specified table in that database has a column matching the specified name that contains a value that matches the specified variable name. Only databases matching these requirements will be present in the query results, so you don't have to worry about null values in the results.
ADDITIONAL EDIT: As promised, here is a sqlserver version.
create procedure FindDatabases
(
@varName varchar(2000),
@tableName varchar(2000),
@columnName varchar(2000)
)
as
begin
declare @selectQuery nvarchar(2000)
-- first, get a list of database names that contain the specified table
IF OBJECT_ID('tempdb.dbo.#db_temp') IS NOT NULL
DROP TABLE #db_temp
CREATE TABLE #db_temp (DatabaseName SYSNAME)
SELECT @selectQuery = (
SELECT '
USE [' + d.name + '];
INSERT INTO #db_temp (DatabaseName)
SELECT DB_NAME() as DatabaseName
WHERE EXISTS(
SELECT 1
FROM sys.objects
WHERE [object_id] = OBJECT_ID(''' + @tableName + ''')
AND [type] = ''U''
)'
FROM sys.databases d
WHERE d.name NOT IN ('master', 'tempdb', 'model', 'msdb')
AND d.state_desc != 'OFFLINE'
FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)')
EXEC sys.sp_executesql @selectQuery
-- use something like mysql's group_concat function to turn that list into a bunch of union all select statements
select
@selectQuery =
(
SELECT LEFT(database_names , LEN(database_names ) - 10) AS database_names
FROM #db_temp AS extern
CROSS APPLY
(
SELECT 'select ''' + DatabaseName + ''' as DatabaseName from ' + DatabaseName + '.dbo.' + @tableName +
' where ' + @columnName + ' = ''' + @varName + '''' + ' union all '
FROM #db_temp AS intern
FOR XML PATH('')
) pre_trimmed (database_names)
GROUP BY database_names
)
drop table #db_temp
-- run those select statements
exec sp_executesql @selectQuery
end
To run it:
exec FindDatabases 'someVar', 'Items', 'ColumnName'
I shamelessly pulled some snippets from here and here to work around the lack of a group_concat function and sqlserver's information_schema having only the local database's info and not sharing information across databases.