Find a database with a particular table OR Find a table in every database of SQL Server - sql

I have a SQL Server with hundreds of databases and each database having hundreds of tables.
Now I would like to find where in these databases is a table that I am looking for.
I could find if a table existed in individual database using
use myDatabase
select * from sys.tables where name = 'mytable'
GO
but using this means I have to manually change the database for hundreds of times .
I would like to find the database name only.
Is there a way out ?

Okay, if you're just wanting to find each database that contains a particular table, and aren't going to be querying the table, then you can just do:
create table #t (
DBName sysname not null
)
go
exec sp_MSforeachdb 'use [?]; if OBJECT_ID(''dbo.mytable'') is not null insert into #t (DBName) select ''?'''
go
select * from #t
go
drop table #t
(If you're not using multiple schemas in your databases, you won't need to specify dbo in the OBJECT_ID call, otherwise I use it to avoid finding tables in the wrong schema)

This should do what you are looking for:
EXEC sp_MSforeachdb "use [?];select * from sys.tables where name='TableName' "
To include the name of the current database in the output use:
EXEC sp_MSforeachdb "use [?];select '[?]' as DatabaseName, * from sys.tables where name='TableName' "

SELECT DISTINCT DB_NAME(database_id)
FROM [sys].[dm_db_index_operational_stats](NULL,NULL,NULL,NULL)
WHERE OBJECT_NAME(object_id,database_id) = 'mytable'

I know this is an old thread but was high on my google search. So I wanted to contribute for others looking to find a database with a certain table in it. These apply to SQL Server 2008 - Current.
I started with this, which worked for my SA level login, but gave me issues with users that did not have permissions to all databases.
SELECT name
FROM sys.databases
WHERE CASE
WHEN state_desc = 'ONLINE' THEN OBJECT_ID( QUOTENAME( name ) + '.[dbo].[mytablename]','U' )
END IS NOT NULL;
But ended up with this adding the HAS_DBACCESS(name) = 1 in restriction so that the query would not fail with a security error.
SELECT name
FROM sys.databases
WHERE HAS_DBACCESS(name) = 1 and
CASE
WHEN state_desc = 'ONLINE' THEN OBJECT_ID( QUOTENAME( name ) + '.[dbo].[mytablename]','U' )
END IS NOT NULL;

exec sp_msforeachdb #command1='
USE ?;
select * from sys.tables where name = ''CLIENTS'''

this is also one of the way, similar with solution of #Jonathan :
exec sp_MSforeachdb 'SELECT "?" AS DB, * FROM [?].sys.tables WHERE name like ''%YourTableName%'''

exec 'select ''?'', name from [?].sys.tables where name = ''yourTable'''

Related

Invalid column name using sp_MSForEachDB in SQL Server 2016

I am attempting to query multiple databases housed on the same SQL Server instance using sp_MSForEachDB.
There are 8 databases that have the table man_days with a column named servicetype. I have manually verified that all 8 tables are identical.
When run the following query I get the error message Invalid column name 'servicetype'
EXEC sp_MSForEachDB
'
BEGIN
IF EXISTS (SELECT * FROM [?].INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = ''man_days'' AND COLUMN_NAME = ''servicetype'')
SELECT top 1 [man_days].[servicetype] from [?]..[man_days]
END
'
The result set is as expected however the error keeps coming up. What am I doing wrong?
Edit... If I change the code to query all columns as in the code below, it works without issue. Or if I change it to query other single columns within that table it works without issues. It only fails when I attempt to select that one column
EXEC sp_MSForEachDB
'
BEGIN
IF EXISTS (SELECT * FROM [?].INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = ''man_days'' AND COLUMN_NAME = ''servicetype'')
SELECT top 1 * from [?]..[man_days]
END
'
[] [1]
Hmmm . . . I think the issue might be a compilation issue. Try this rather alternative
EXEC sp_MSForEachDB
'
BEGIN
IF EXISTS (SELECT * FROM [?].INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = ''man_days'' AND COLUMN_NAME = ''servicetype'')
BEGIN
DECLARE #sql NVARCHAR(MAX);
SET #sql = ''SELECT top 1 [man_days].[servicetype] from [db]..[man_days]'';
REPLACE(#sql, ''[db]'', ?);
EXEC sp_executesql #sql;
END;
END
';
That is, turn the SELECT into dynamic SQL, so it is not evaluated at the same time as the IF.
I'm going to guess it is permissions on the metadata for one or more of the databases.
The visibility of the metadata in information schema views is limited to securables that a user either owns or on which the user has been granted some permission. For more information, see Metadata Visibility Configuration.
It may be the specific permission that your login then has on that table that restricts whether you can see the column names. VIEW DEFINITION permission I think will be required so that this error isn't shown.

SQL request over multiple databases and tables

I'm having quite the problem.
The process data from our machines is stored in multiple MS SQL Databases.
It is possible to mount and unmount data which is no longer used or which should be archived.
Thats the reason, why there are multiple databases.
In each Database there exists multiple tables with the data values for one or more measuring points.
Which a JOIN Query i can get the values from one table with the corresponding table and tagname:
> SELECT HA_DATA_yyyy.R_xxxxx.time HA_DATA_yyyy.R_xxxxx.value, HA_DATA_yyyy.tags.tagname FROM HA_DATA_yyyy.R_xxxxx
> INNER JOIN HA_DATA_yyyy.RI_xxxxx ON HA_DATA_yyyy.R_xxxxx.id = HA_DATA_yyyy.RI_xxxxx.id
> INNER JOIN HA_DATA_yyyy.tags on HA_DATA_yyyy.RI_xxxxx.tag_uuid = HA_DATA_yyyy.tags.tag_uuid
> WHERE (HA_DATA_yyyy.tags.tagname like 'tagname')
yyyy - represents a number for the database
xxxxx - represents a number which is unique on the database-server, but differents in each database.
But now I'm looking for a solution to get this for all R_xxxxx tables of a database and for all mounted databases.
Is there any way to do this without external software? Just with the right query request or user defined function / stored procedure?
maybe dynamic sql is an option.
as a starting point you could use the list of databases:
insert into #dblist (dbname)
select d.name from sys.databases d where d.name like 'HA_DATA_%'
then for each database gather the list of tables to read data from (you can go with cursors or other loop as you prefer):
declare #dbname varchar(128) = ''
declare #dynsql nvarchar(max)
create table #listoftables (name varchar(128), db varchar(128))
while exists(select top 1 dbname from #dblist where dbname > #dbname order by dbname)
begin
set #dynsql = 'insert into #listoftables(name,db) select name,''' + #db + ''' from '+ #db +'.sys.tables'
exec sp_executesql #statement = #dynsql
-- move on to next db
select top 1 #dbname = dbname from #dblist where dbname > #dbname order by dbname
end
now you have a table list to loop onto to build a dynamic query to read all the data at once.
beware of the many issues you may incur using dynamic sql; here and there you can find just the first 2 results gathered with some explanations on why you have to be careful using dynamic sql.
Please have a look at the answer of this Stackoverflow question:
Archiving large amounts of old data in SQL Server
I think it might be what you need.
Update:
You can query the mounted databases by using the SQL query:
select Name into #myDatabases -- get all mounted databases into #myDatabases
from sys.databases
where (has_dbaccess(name) > 0)
and name not in ('master', 'tempdb', 'model', 'msdb')
order by 1
select * from #myDatabases -- list all mounted databases
drop table #myDatabases -- don't forget to drop it at the end
This can be used to create a dynamic SQL statement, which you execute via the sp_executesql command:
EXECUTE sp_executesql #SQL_String, #Parameter_Definition, #Param1, ..., #ParamN
The parameter definition is a string containing the list of parameter names and their datatypes.
So you can build up your own query based on the database list above and then execute it.

Search of table names

I use the following to search for strings within the stored procedures of a specific database:
USE DBname
SELECT Name
FROM sys.procedures
WHERE OBJECT_DEFINITION(OBJECT_ID) LIKE '%xxx%'
Is it easy to amend the above so that it searches Table names in a specific db "DBname" ?
I'm using this and works fine
SELECT * FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_NAME LIKE '%%'
select name
from DBname.sys.tables
where name like '%xxx%'
and is_ms_shipped = 0; -- << comment out if you really want to see them
If you want to look in all tables in all Databases server-wide and get output you can make use of the undocumented sp_MSforeachdb procedure:
sp_MSforeachdb 'SELECT "?" AS DB, * FROM [?].sys.tables WHERE name like ''%Table_Names%'''
You can also use the Filter button to filter tables with a certain string in it.
You can do the same with stored procedures and views.
I am assuming you want to pass the database name as a parameter and not just run:
SELECT *
FROM DBName.sys.tables
WHERE Name LIKE '%XXX%'
If so, you could use dynamic SQL to add the dbname to the query:
DECLARE #DBName NVARCHAR(200) = 'YourDBName',
#TableName NVARCHAR(200) = 'SomeString';
IF NOT EXISTS (SELECT 1 FROM master.sys.databases WHERE Name = #DBName)
BEGIN
PRINT 'DATABASE NOT FOUND';
RETURN;
END;
DECLARE #SQL NVARCHAR(MAX) = ' SELECT Name
FROM ' + QUOTENAME(#DBName) + '.sys.tables
WHERE Name LIKE ''%'' + #Table + ''%''';
EXECUTE SP_EXECUTESQL #SQL, N'#Table NVARCHAR(200)', #TableName;
If you prefer case-insensitive searching:
SELECT * FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_NAME ILIKE '%%'
or
SELECT * FROM INFORMATION_SCHEMA.TABLES
WHERE Lower(TABLE_NAME) LIKE Lower('%%')
Adding on to #[RichardTheKiwi]'s answer.
Whenever I search for a list of tables, in general I want to select from all of them or delete them. Below is a script that generates those scripts for you.
The generated select script also adds a tableName column so you know what table you're looking at:
select 'select ''' + name + ''' as TableName, * from ' + name as SelectTable,
'delete from ' + name as DeleteTable
from sys.tables
where name like '%xxxx%'
and is_ms_shipped = 0;
you can also use the show command.
show tables like '%tableName%'
I want to post a simple solution for every schema you've got. If you are using MySQL DB, you can simply get from your schema all the table's name and add the WHERE-LIKE condition on it. You also could do it with the usual command line as follows:
SHOW TABLES WHERE tables_in_<your_shcema_name> LIKE '%<table_partial_name>%';
where tables_in_<your_shcema_name> returns the column's name of SHOW TABLES command.
You can use below :
Select * from sys.tables where name like '%yourtablename%'
This will working fine....
SELECT * FROM sys.TABLES
WHERE name LIKE '%%'

Create view from data accross multiple databases

After some searching around i couldn't find a good answer that covers my issue.
I am working on the consolidation of around 100 databases. The structure is the same and they are all on the same server. All the databases have a table with login information.
We have created a core database with all the connection information from the other databases.
Now we need to create a view in the core database that contains all the login credentials from all the databases.
This means we need to use a loop to go through all the databases and select the user name and password.
Any ideas or suggestions are welcome
One possible solution is to create a stored procedure
DECLARE #sql varchar(max), #Database1 varchar(300)
set #Database1 = 'tempdb'
SET #sql='
USE '+#Database1+';
IF EXISTS (SELECT 1 FROM SYS.VIEWS WHERE NAME =''test_view'')
BEGIN
DROP VIEW test_view
PRINT ''VIEW EXISTS''
END'
PRINT #sql
EXEC(#sql)
declare #sql1 varchar(max)
// Modify below query as per your requirement its just for an idea
select #sql1 = IsNull(#sql1 + 'union all ','') +
'select * from ' + name + '.dbo.tblUser'
from sys.databases
where name like 'DbNamePrefix%'
set #sql1 = 'create view dbo.YourView as ' + #sql1
exec (#sql1)
Make a database job and schedule it as per your requirement.
To reference to your tables in the second database use this:
[DBName].[dbo].[TableName]
e.g.
CREATE VIEW [dbo].[ViewName]
as
select
a.ID,
a.Name,
b.Address
from TableA a
join SecondDBName.dbo.Table b
on ... ---Remaining code here...
NOTE: This will work only on the same server - if your databases are on different servers then you will need to create a linked server.
Take a look at this. Can this be one of the answers to your question?
http://blog.springsource.org/2007/01/23/dynamic-datasource-routing/

SQL Server - Return SCHEMA for sysobjects

How to I get the SCHEMA when doing a select on sysobjects?
I am modifing a stored procedure called SearchObjectsForText which returns only the Name but I would also like to include the SCHEMA.
Right now it is doing something similar to this:
SELECT DISTINCT name
FROM sysobjects
I would like to know what tables need to be joined to return the SCHEME for each 'name'.
If you mean SQL Server 2005 or higher, use sys.objects instead of sysobjects:
SELECT sys.objects.name, sys.schemas.name AS schema_name
FROM sys.objects
INNER JOIN sys.schemas ON sys.objects.schema_id = sys.schemas.schema_id
2005 introduced schemas. up to 2000, users equaled schemas. The same query for SQL Server 2000:
SELECT sysusers.name AS OwnerName, sysobjects.name
FROM sysobjects
INNER JOIN sysusers ON sysobjects.uid = sysusers.uid
On Sql Server 2005 (and above) you can use the sys.objects view:
select
name as ObjectName,
schema_Name(schema_id) as SchemaName
from
sys.objects
In Sql Server 2000 (and below), "schema" had a different conceptual meaning. Note from MSDN:
In earlier releases of SQL Server, databases could contain an entity called a "schema", but that entity was effectively a database user. SQL Server 2005 is the first release of SQL Server in which a schema is both a container and a namespace.
Could you use the Information_Schema view(s) instead?
SELECT DISTINCT table_name, table_schema
FROM INFORMATION_SCHEMA.TABLES
According to the MSDN page (for SQL Server 2008 and above),
Do not use INFORMATION_SCHEMA views to determine the schema of an object. The only reliable way to find the schema of a object is to query the sys.objects catalog view.
However, it seems that they're probably referring to an issue where you have a table name and are trying to find its schema, which wouldn't work if there were multiple tables with the same name (in different schemas). If you're querying for multiple results (not just trying to find the schema for a specific table), then it should be fine.
I would favor using the more focused "sys" views - sys.procedures instead of sys.objects. You'll need to join it with the sys.schemas view to get schema name and such.
select
p.name,
s.name 'Schema',
p.type_desc, p.create_date, p.modify_date
from
sys.procedures p
inner join
sys.schemas s ON p.schema_id = s.schema_id
I would start to get away from using "sysobjects" since Microsoft clearly states in Books Online that "sysobjects" is subject to removal in a future release:
This SQL Server 2000 system table is included as a view for backward compatibility. We recommend that you use the current SQL Server system views instead. To find the equivalent system view or views, see Mapping SQL Server 2000 System Tables to SQL Server 2005 System Views. This feature will be removed in a future version of Microsoft SQL Server. Avoid using this feature in new development work, and plan to modify applications that currently use this feature.
Marc
Just to repeat what's already been suggested here, here's what I've used, to get a list of Tables, Stored Procedures, Views and Functions in my database:
SELECT schema_Name(schema_id) as SchemaName,
[name], -- Name of the Table, Stored Procedure or Function
[type] -- 'V' for Views, 'U' for Table, 'P' for Stored Procedure, 'FN' for function
FROM sys.objects
WHERE [type_desc] IN ( 'USER_TABLE', 'SQL_STORED_PROCEDURE', 'VIEW', 'SQL_SCALAR_FUNCTION')
AND [name] NOT LIKE 'sp_%'
AND [name] NOT LIKE 'fn_%'
ORDER BY 3 DESC, -- type first
1 ASC, -- then schema
2 ASC -- then function/table name
...and here's what our good friend Northwind would return...
In SQL 200:
select DISTINCT
name as ObjectName,
USER_NAME(uid) as SchemaName
from
sysobjects
In earlier releases of SQL Server, databases could contain an entity called a "schema", but that entity was effectively a database user.
Have included an option to delete all objects starting with certain prefix and optionally from certain schema.
By the way, I added extra query to get all types which are not stored on sysobjects by default.
I have uploaded entire sample script to GitHub:
DropAll_Dnn_Objects.sql
Part 1: Temporary Stored Procedure:
IF OBJECT_ID('_temp_DropAllDnnObjects') IS NOT NULL
DROP PROCEDURE _temp_DropAllDnnObjects;
GO
CREATE PROCEDURE _temp_DropAllDnnObjects
#object_prefix NVARCHAR(30),
#schema_name sysname = NULL
AS
BEGIN
DECLARE #sname sysname, #name sysname, #type NVARCHAR(30)
DECLARE #object_type NVARCHAR(255), #sql NVARCHAR(2000), #count INT = 0
DECLARE curs CURSOR FOR
SELECT sname, [name], xtype
FROM (
SELECT SCHEMA_NAME(schema_id) as sname, [name], [type] as xtype
FROM sys.objects
WHERE [type] IN ('U', 'P', 'FN', 'IF', 'TF', 'V', 'TR')
AND name LIKE #object_prefix + '%'
AND (#schema_name IS NULL OR schema_id = SCHEMA_ID(#schema_name))
UNION ALL
SELECT SCHEMA_NAME(schema_id) as sname, [name], 'TYPE' as xtype
FROM sys.types
WHERE is_user_defined = 1
AND [name] LIKE #object_prefix + '%'
AND (#schema_name IS NULL OR schema_id = SCHEMA_ID(#schema_name))
) a
ORDER BY CASE xtype
WHEN 'P' THEN 1
WHEN 'FN' THEN 2
WHEN 'IF' THEN 3
WHEN 'TF' THEN 4
WHEN 'TR' THEN 5
WHEN 'V' THEN 6
WHEN 'U' THEN 7
WHEN 'TYPE' THEN 8
ELSE 9
END, name
OPEN curs;
FETCH NEXT FROM curs INTO #sname, #name, #type;
WHILE ##FETCH_STATUS = 0
BEGIN
SET #count = #count + 1
-- Configuration point 2
SET #object_type = CASE #type
WHEN 'P' THEN 'PROCEDURE'
WHEN 'FN' THEN 'FUNCTION'
WHEN 'IF' THEN 'FUNCTION'
WHEN 'TF' THEN 'FUNCTION'
WHEN 'TR' THEN 'TRIGGER'
WHEN 'V' THEN 'VIEW'
WHEN 'U' THEN 'TABLE'
WHEN 'TYPE' THEN 'TYPE'
END
SET #sql = REPLACE(REPLACE(REPLACE('DROP <TYPE> [<SCHEMA>].[<NAME>];',
'<TYPE>', #object_type),
'<SCHEMA>', #sname),
'<NAME>', #name)
BEGIN TRY
PRINT #sql
EXEC(#sql)
END TRY
BEGIN CATCH
PRINT 'ERROR: ' + ERROR_MESSAGE()
END CATCH
FETCH NEXT FROM curs INTO #sname, #name, #type;
END;
PRINT CONCAT('Objects Found: ', #Count)
PRINT ''
PRINT '------------------------------------------------------'
PRINT ''
CLOSE curs;
DEALLOCATE curs;
RETURN #Count
END;
GO
It will continue on errors (and display the error message). It will return a count of all objects found.
Part 2: Call Stored Procedure with parameters:
You can create a WHILE loop in order to run the command until no object is left (dependencies), as follows:
DECLARE #count INT = 1
WHILE #count > 0 EXEC #count = _temp_DropAllDnnObjects 'dnn';
SET #count = 1
WHILE #count > 0 EXEC #count = _temp_DropAllDnnObjects 'aspnet';
SET #count = 1
WHILE #count > 0 EXEC #count = _temp_DropAllDnnObjects 'vw_aspnet';
GO
Part 3: Finally, get rid of the procedure:
IF OBJECT_ID('_temp_DropAllDnnObjects') IS NOT NULL
DROP PROCEDURE _temp_DropAllDnnObjects;
GO
Instead of a view, why not use this to populate a temporary table you can use?
This is the solution I use in stored procedures
This is the best way to get a schema dynamically and add it to the different tables within a database in order to get other information dynamically
select #sql = 'insert #tables SELECT ''[''+SCHEMA_NAME(schema_id)+''.''+name+'']'' AS SchemaTable FROM sys.tables'
exec (#sql)
of course #tables is a dynamic table in the stored procedure