Find table name in all objects of all databases - sql-server

I have a system with multiple databases and client applications. All databases are at one SQL Server instance. They have been developed by different people at different time. So if some error occur it is pritty hard to find in which procedure or trigger the data was modified.
Now I use this script, which I found on this site:
SELECT DISTINCT ISNULL(sd.referenced_schema_name+'.','')+ OBJECT_NAME(sd.referenced_id)TableName,
OBJECT_NAME(sd.referencing_id)Ref_Object,
CASE WHEN OBJECTPROPERTYEX(sd.referencing_id,N'IsUserTable')= 1
THEN'Table'
WHEN OBJECTPROPERTYEX(sd.referencing_id,N'IsTableFunction')= 1
THEN'Function'
WHEN OBJECTPROPERTYEX(sd.referencing_id,N'IsTableFunction')= 1
THEN'Function'
WHEN OBJECTPROPERTYEX(sd.referencing_id,N'IsScalarFunction')=1
THEN'Function'
WHEN OBJECTPROPERTYEX(sd.referencing_id,N'IsTrigger')= 1
THEN'Trigger'
WHEN OBJECTPROPERTYEX(sd.referencing_id,N'IsView')= 1
THEN'View'
WHEN OBJECTPROPERTYEX(sd.referencing_id,N'IsUserTable')= 1
THEN'Table'
WHEN OBJECTPROPERTYEX(sd.referencing_id,N'IsProcedure')= 1
THEN'Procedure'
WHEN OBJECTPROPERTYEX(sd.referencing_id,N'IsIndexed')= 1
THEN'Index'
WHEN OBJECTPROPERTYEX(sd.referencing_id,N'IsForeignKey')= 1
THEN'ForeignKey'
WHEN OBJECTPROPERTYEX(sd.referencing_id,N'IsPrimaryKey')= 1
THEN'PrimaryKey'
END AS Ref_Object_Name
FROM sys.sql_expression_dependencies SD
INNER JOIN sys.objects obj
ON obj.object_id=sd.referenced_id
WHERE obj.is_ms_shipped= 0
and referenced_id=object_id('TABLE_NAME') /*Where one can Replace table Name*/
AND obj.type_desc='USER_TABLE'
ORDER BY TableName,Ref_Object,Ref_Object_Name
But this script seems to work only for the database to which the table belong.
I want to get for a specified table name (or even better for an object) list of all objects of all databases in which the specified table name met:
Database_Name SchemaName ObjectName ObjectKind
Thanks.

DECLARE #table_name SYSNAME = N'%';
DECLARE #sql NVARCHAR(MAX) = N'';
SELECT #sql += 'SELECT DISTINCT Database_Name = ''' + QUOTENAME(name) + ''',
COALESCE(sd.referenced_schema_name +''.'', '''')+ o.name AS TableName,
r.name AS Ref_Object,
r.type_desc AS Ref_Object_Name
FROM ' + QUOTENAME(name) + '.sys.sql_expression_dependencies AS sd
INNER JOIN ' + QUOTENAME(name) + '.sys.objects AS o
ON o.object_id = sd.referenced_id
INNER JOIN ' + QUOTENAME(name) + '.sys.objects AS r
ON sd.referencing_id = r.object_id
WHERE o.is_ms_shipped = 0
and referenced_id = o.object_id
AND o.type_desc = ''USER_TABLE''
AND o.name LIKE ''' + #table_name + '''
UNION ALL
'
FROM sys.databases
WHERE database_id BETWEEN 5 AND 32766;
SET #sql = LEFT(#sql, LEN(#sql)-11)
+ 'ORDER BY Database_Name, TableName,Ref_Object,Ref_Object_Name';
EXEC sp_executesql #sql;
EDIT
The above will find all the references within each database, but won't find cross-database references. It took a little playing, and the output isn't precisely what you wanted, but I think it makes it more self-explanatory:
DECLARE #table_name SYSNAME = N'%'; -- find all
CREATE TABLE #d
(
db SYSNAME,
[object_id] INT,
sch SYSNAME,
obj SYSNAME,
ref_db NVARCHAR(128),
ref_sch NVARCHAR(128),
ref_obj NVARCHAR(128),
ref_object_id INT,
type_desc SYSNAME
);
DECLARE #sql NVARCHAR(MAX) = N'';
SELECT #sql += 'SELECT ''' + QUOTENAME(name) + ''',
d.referencing_id,
QUOTENAME(s.name),
QUOTENAME(o.name),
QUOTENAME(d.referenced_database_name),
QUOTENAME(d.referenced_schema_name),
QUOTENAME(d.referenced_entity_name),
d.referenced_id,
o.type_desc
FROM ' + QUOTENAME(name)
+ '.sys.sql_expression_dependencies AS d
INNER JOIN ' + QUOTENAME(name)
+ '.sys.objects AS o
ON d.referencing_id = o.[object_id]
INNER JOIN '
+ QUOTENAME(name) + '.sys.schemas AS s
ON o.[schema_id] = s.[schema_id]
WHERE d.referenced_entity_name LIKE ''' + #table_name + '''
UNION ALL
'
FROM sys.databases WHERE database_id BETWEEN 5 AND 32766;
SET #sql = LEFT(#sql, LEN(#sql)-11);
INSERT #d EXEC sp_executesql #sql;
SELECT
db+'.'+sch+'.'+obj,
' (' + type_desc + ') references => ',
COALESCE(ref_db, db)+'.'+ref_sch+'.'+ref_obj
FROM #d;
GO
DROP TABLE #d;
GO
Sample output:
[db1].[dbo].[foo] (SQL_STORED_PROCEDURE) references => [db2].[dbo].[bar]
[db1].[dbo].[xyz] (SQL_STORED_PROCEDURE) references => [db1].[dbo].[table_xyz]

This should help you get started
create table ##tbData (
DatabaseName Varchar(64),
objectName varchar(128),
ObjectKind varchar(128)
)
go
EXEC sp_Msforeachdb "use [?];
insert ##tbData select db_name(),so.name,so.xtype from sysobjects so"
select * from ##tbdata
Essentially, build a table and the SQL statement you want to use, then use the undocumented sp_MSforEachdb to load the table from every database

You could look at something like sp_MSForeachdb and call the above query each of those databases.

Related

How to Select tables names to this query

I want to select phone numbers from all tables in my databese and names of these tables too. I write a query that shows me all phone_numbers but I dont't know how to select table name to each phone number. This is my query:
DECLARE #SQL AS VarChar(MAX)
SET #SQL = ''
SELECT #SQL = #SQL + 'SELECT phone_number FROM ' + TABLE_SCHEMA + '.[' + TABLE_NAME + ']' + CHAR(13)
FROM INFORMATION_SCHEMA.TABLES where table_name in (select table_name
from information_schema.columns
where column_name = 'phone_number'
)
You can simply add the table name as a constant to the SELECT clause. But, I presume you're going to want to run this query, which means you have a few more things to change:
You're probably going to want sp_executesql, which requires a Unicode variable. So, you need to DECLARE #SQL NVARCHAR(MAX).
Do you want one result set or multiple result sets? I'm guessing you want all the results in one result set, which means you're going to want to use UNION ALL between the parts of the query.
So, try something like this:
DECLARE #sql NVARCHAR(MAX)
SET #sql = N'SELECT '''' AS table_name, '''' AS phone_number FROM [dbo].[SomeTable] WHERE 1 = 0'
DECLARE #table_name SYSNAME
DECLARE cur CURSOR LOCAL FAST_FORWARD FOR
SELECT table_name
FROM INFORMATION_SCHEMA.columns
WHERE column_name = 'phone_number'
OPEN cur
FETCH NEXT FROM cur INTO #table_name
WHILE ##FETCH_STATUS = 0
BEGIN
SET #sql = #sql + N' UNION ALL SELECT ''' + #table_name + N''', phone_number FROM [' + #table_name + N']'
FETCH NEXT FROM cur INTO #table_name
END
CLOSE cur
DEALLOCATE cur
EXEC sp_executesql #sql
When I used [dbo].[SomeTable], just use some table that you know exists. You would also need to modify the query if you want fully-qualified table names, but the above should get you started.
Another solution without CURSOR. You could combine each query with UNION like this.
--SELECT DISTINCT phone_number FROM dbo.Course c
DECLARE #sql nvarchar(max) = ''
SELECT #sql = #sql + N' SELECT DISTINCT phone_number, '''+ s.name + '.' + t.name + ''' AS TableName
FROM '+ s.name + '.' + t.name + Char(13) + ' UNION' + char(13)
FROM sys.tables t
INNER JOIN sys.schemas s ON t.schema_id = s.schema_id
INNER JOIN sys.columns c ON c.object_id = t.object_id
WHERE c.name ='phone_number'
IF(#sql != '')
BEGIN
SET #sql = LEFT(#sql,len(#sql) - 6) -- remove last UNION
PRINT #sql
-- execute sql
EXEC sp_executesql #sql
END
I also add column TableName: Table of phone_number
If you want TableName if the first column then change it
SELECT #sql = #sql + N' SELECT DISTINCT '''+ s.name + '.' + t.name + ''' AS TableName, phone_number
FROM '+ s.name + '.' + t.name + Char(13) + ' UNION' + char(13)

Testing Datawarehouse to see what see what issues might have occurred after nightly jobs have run

I want to be able test all tables in the Data warehouse to see what has changed after nightly jobs have run. I am using the query below to see what tables have no rows however i'd like to expand the testing to see other things such as what fields have null values after the job has run. does anyone do similar testing and have a script that they use for this or any other things I should test for?
select
t.name table_name,
s.name schema_name,
sum(p.rows) total_rows
from
sys.tables t
join sys.schemas s on (t.schema_id = s.schema_id)
join sys.partitions p on (t.object_id = p.object_id)
where p.index_id in (0,1)
group by t.name,s.name
having sum(p.rows) = 0;
i've written the following stored proc that checks all tables in my DWH to see what columns are null. similarly the same can be done for checking what numeric columns are zero.
alter PROCEDURE EMPTYSEARCH
#WHICHTABLE VARCHAR(50)
AS
SET NOCOUNT ON
DECLARE #SQL nVARCHAR(max),
#TABLENAME VARCHAR(max) ,
#COLUMNNAME VARCHAR(max)
CREATE TABLE #RESULTS(TBLNAME VARCHAR(60),COLNAME VARCHAR(60),SQL VARCHAR(600))
SELECT
SYSOBJECTS.NAME AS TBLNAME,
SYSCOLUMNS.NAME AS COLNAME,
TYPE_NAME(SYSCOLUMNS.XTYPE) AS DATATYPE
INTO #FKFINDER
FROM SYSOBJECTS
INNER JOIN SYSCOLUMNS ON SYSOBJECTS.ID=SYSCOLUMNS.ID
WHERE SYSOBJECTS.XTYPE='U'
AND SYSOBJECTS.NAME = #WHICHTABLE
AND TYPE_NAME(SYSCOLUMNS.XTYPE) IN ('VARCHAR','NVARCHAR','CHAR','NCHAR')
ORDER BY TBLNAME,COLNAME
DECLARE C1 CURSOR FOR
SELECT TBLNAME,COLNAME FROM #FKFINDER ORDER BY TBLNAME,COLNAME
OPEN C1
FETCH NEXT FROM C1 INTO #TABLENAME,#COLUMNNAME
WHILE ##FETCH_STATUS <> -1
BEGIN
SET #SQL = '
IF EXISTS(SELECT * FROM [' + #TABLENAME + '] WHERE (select count(*) from [' + #TABLENAME + '] where [' + #COLUMNNAME + '] is null) = (select count(*) from [' + #TABLENAME + '] ))
INSERT INTO #RESULTS(TBLNAME,COLNAME,SQL) VALUES(''' + #TABLENAME + ''',''' + #COLUMNNAME + ''',''
SELECT * FROM [' + #TABLENAME + '] WHERE (select count(*) from [' + #TABLENAME + '] where [' + #COLUMNNAME + '] is null) = (select count(*) from [' + #TABLENAME + '] '') ;'
PRINT #SQL
EXEC (#SQL)
FETCH NEXT FROM C1 INTO #TABLENAME,#COLUMNNAME
END
CLOSE C1
DEALLOCATE C1
SELECT * FROM #RESULTS

Create function that can be run with any database

How can I create a function that can be run against any database on my server?
Here's an example, I want to specify a column name to search for, and which database to search in:
CREATE FUNCTION dbo.fn_FindColumnsInAllTables
(
#ColumnName NVARCHAR(255)
)
RETURNS TABLE
AS
RETURN
(
SELECT
c.name AS 'ColumnName'
,t.name AS 'TableName'
FROM
sys.columns c
JOIN
sys.tables t
ON
c.object_id = t.object_id
WHERE
c.name LIKE '%' + #ColumnName + '%'
)
Taking the excellent advice from HLGEM to use a procedure instead this is quite easy. This example not only works it is also sql injection proof. I use QUOTENAME around the database name itself and then parameterize the column name in the dynamic sql.
create procedure FindColumn
(
#DBName sysname
, #ColName sysname
) as
declare #SQL nvarchar(max);
if exists(select * from sys.databases where name = #DBName)
begin
set #SQL = 'select t.name as TableName
, c.name as ColumnName
from ' + QUOTENAME(#DBName) + '.sys.tables t
join ' + QUOTENAME(#DBName) + '.sys.columns c on c.object_id = t.object_id
where c.name = #ColName'
exec sp_executesql #SQL, N'#ColName sysname', #ColName = #ColName
end
else
select 'Database not found'
GO
exec FindColumn 'YourDatabaseName', 'YourColumn'

SQL Server - find all tables in database with unique ID value

I want to find out all the tables in the database (in SQLServer) that has the column IDName with particular value 'SAM', like so IDName='SAM'. So my initial apporach was create a table with all the tables that have the column "IDName" (since not all the tables in the database has this column. Then i was thinking of going through each table to see which tables match the IDName='SAM' - This is where i'm stuck. I'm pretty sure there is a lot faster way of doing this too but im not too familiar with database query coding. Anything will help Thanks!
select * into tmp from
(
SELECT SO.NAME AS TableName, SC.NAME AS ColumnName
FROM dbo.sysobjects SO INNER JOIN dbo.syscolumns SC ON SO.id = SC.id
WHERE sc.name = 'IDName' and SO.type = 'U'
) tablelist
So if I go Select * from tmp, I get the list of tables that have the column "IDName". Now I have to go through each one of that list and see if they have "IDName = 'Sam'" if they do add it to the output table. In the end I want to see all the names of the tables from the database that has the IDName 'Sam'.
DECLARE #sql AS varchar(max) = '';
DECLARE #ColumnName AS varchar(100) = 'IDName'
DECLARE #ResultQuery AS varchar(max) = 'SELECT ''#TableName'' AS TableName ' +
' ,#ColumnName ' +
'FROM #TableName ' +
'WHERE #ColumnName = ''SAM''';
SET #ResultQuery = REPLACE(#ResultQuery, '#ColumnName', QUOTENAME(#ColumnName));
WITH AllTables AS (
SELECT SCHEMA_NAME(Tables.schema_id) AS SchemaName
,Tables.name AS TableName
,Columns.name AS ColumnName
FROM sys.tables AS Tables
INNER JOIN sys.columns AS Columns
ON Tables.object_id = Columns.object_id
WHERE Columns.name = #ColumnName
)
SELECT #sql = #sql + ' UNION ALL ' +
REPLACE(#ResultQuery, '#TableName', QUOTENAME(TableName)) + CHAR(13)
FROM AllTables
SET #sql = STUFF(#sql, 1, LEN(' UNION ALL'), '');
--PRINT #sql;
SET #sql =
'WITH AllTables AS ( ' +
#sql +
') ' +
'SELECT DISTINCT TableName ' +
'FROM AllTables ';
EXEC (#sql)

select all databases in sysobjects that have a table named 'mytable' regardless of schema?

For a given sql 2000 - 2008 server I want to find any table named dbo.[MyTable] on that server. In addition, how do I find all databases that have a table named [dbo].[MyTable] and [AnySchemaName].[MyTable]. Is there a simple sp_ command like spTables MyTable? Or 'sp_AllDatabaseTable [MyTable]'?
I want to print it out like:
ServerName Database SchemaName MyTable Date Created
----------- --------- ----------- --------- -------------
Thx
I really would prefer a solution that does not use either CURSORS nor sp_msforeachdb.
The solution below is gives you an idea, and you can adapt it to your own needs.
USE [master]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
BEGIN TRY
SET NOCOUNT ON
SET DATEFORMAT DMY
SET DEADLOCK_PRIORITY NORMAL;
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED
DECLARE #log NVARCHAR(MAX)
,#vCrlf CHAR(2);
SELECT #log = ''
,#vCrlf = CHAR(13)+CHAR(10);
DECLARE #SQL NVARCHAR(MAX)
BEGIN TRY DROP TABLE #OBJECTS END TRY BEGIN CATCH END CATCH
CREATE TABLE #OBJECTS(
DB_ID INT,
OBJECT_ID INT,
S_NAME SYSNAME,
NAME SYSNAME,
ROW_COUNT INT,
STATISTICS_UPDATED DATETIME)
SELECT #SQL = '
SELECT db_id=db_id(),
o.object_id,
s_name=s.name,
o.name,
ddps.row_count
,[Statistics_Updated]=STATS_DATE(I.OBJECT_ID,I.INDEX_ID)
FROM sys.indexes AS i
INNER JOIN sys.objects AS o ON i.OBJECT_ID = o.OBJECT_ID
INNER JOIN sys.schemas s ON s.schema_id = o.schema_id
INNER JOIN sys.dm_db_partition_stats AS ddps ON i.OBJECT_ID = ddps.OBJECT_ID
AND i.index_id = ddps.index_id
WHERE i.index_id < 2
AND o.is_ms_shipped = 0
'
set #SQL = (
SELECT STUFF(
(SELECT N' ' + ' USE ' + QUOTENAME(name) +';' + #vCrlf + #SQL + #vCrlf
FROM SYS.DATABASES SD
WHERE SD.STATE_DESC = 'ONLINE' -->Skips the database if it is not online
AND SD.COMPATIBILITY_LEVEL > 80
AND SD.database_id > 3 -- NO MASTER NOR TEMPDB NOR MODEL
FOR XML PATH(''),TYPE)
.value('text()[1]','nvarchar(max)'),1,2,N'')
)
INSERT INTO #OBJECTS
( [db_id],
[object_id],
[s_name],
[name],
[row_count],
[Statistics_Updated]
)
EXECUTE MASTER.DBO.sp_executesql #SQL
SELECT * FROM #OBJECTS
--WHERE NAME = 'THE NAME THAT I AM LOOKING FOR'
END TRY
BEGIN CATCH
PRINT '--EXCEPTION WAS CAUGHT--' + CHAR(13) +
'THE ERROR NUMBER:' + COALESCE(CAST ( ERROR_NUMBER() AS VARCHAR), 'NO INFO') + CHAR(13)
PRINT 'SEVERITY: ' + COALESCE(CAST ( ERROR_SEVERITY() AS VARCHAR), 'NO INFO') + CHAR(13) +
'STATE: ' + COALESCE(CAST ( ERROR_STATE() AS VARCHAR), 'NO INFO') + CHAR(13)
PRINT 'PROCEDURE: ' + COALESCE(CAST ( COALESCE(ERROR_PROCEDURE(),'NO INFO') AS VARCHAR), 'NO INFO') + CHAR(13) +
'LINE NUMBER: ' + COALESCE(CAST ( ERROR_LINE() AS VARCHAR), 'NO INFO') + CHAR(13)
PRINT 'ERROR MESSAGE: '
PRINT CAST ( COALESCE(ERROR_MESSAGE(),'NO INFO') AS NTEXT)
END CATCH;
I prefer a set based approach:
Declare #TableName as Varchar(255)
Set #TableName = '<MyTableName>'
Declare #SQL as Varchar(max)
Select #SQL = Coalesce(#SQL + '
', '') +
CASE
WHEN Row_Number() Over (Order by Database_ID) = 1
THEN ''
ELSE
'UNION ALL '
END +
'SELECT
''' + d.Name + ''' as DatabaseName
, s.Name as SchemaName
, o.Name as TableName
FROM ' + d.Name +'.Sys.Objects o
INNER JOIN ' + d.Name + '.Sys.Schemas s
ON o.Schema_ID = s.Schema_ID
WHERE o.Name like ''' + #TableName + ''''
FROM sys.databases d
where d.Name not like 'ReportServer%'
and d.Name not like 'SSISPackageRegistry'
Print #SQL
EXEC(#SQL)
Of course, you can use sp_msforeachdb for this purpose but you need to remember that fhis function is neither documented nor officially supported. Also, sometimes it breaks. More about it here Making a more reliable and flexible sp_MSforeachdb
You can use this script to search table by name in all databases.
I took it from Find table in every database of SQL server
DECLARE #TableName VARCHAR(256)
SET #TableName='YOUR_TABLE_NAME'
DECLARE #DBName VARCHAR(256)
DECLARE #varSQL VARCHAR(512)
DECLARE #getDBName CURSOR
SET #getDBName = CURSOR FOR
SELECT name
FROM sys.databases
CREATE TABLE #TmpTable (DBName VARCHAR(256),
SchemaName VARCHAR(256),
TableName VARCHAR(256),
create_date date, modify_date date)
OPEN #getDBName
FETCH NEXT
FROM #getDBName INTO #DBName
WHILE ##FETCH_STATUS = 0
BEGIN
SET #varSQL = 'USE ' + #DBName + ';
INSERT INTO #TmpTable
SELECT '''+ #DBName + ''' AS DBName,
SCHEMA_NAME(schema_id) AS SchemaName,
name AS TableName,
create_date, modify_date
FROM sys.tables
WHERE name LIKE ''%' + #TableName + '%''' --WHERE name = '' + #TableName + ''' /* if you want to search by exact table name*/
EXEC (#varSQL)
FETCH NEXT
FROM #getDBName INTO #DBName
END
CLOSE #getDBName
DEALLOCATE #getDBName
SELECT *
FROM #TmpTable
DROP TABLE #TmpTable
Also, you may want to read this Find table name in all objects of all databases
I'd have said
sp_msforeachdb 'Select * from Sysobjects where name=''MyTable'''
But you don't need to, sysobjects is in the master table and does it for all databases anyway.
You should be able find the other columns easily enough.

Resources