Get number of tables in each database in SQL Server - sql-server

SELECT d.NAME
,ROUND(SUM(mf.size) * 8 / 1024, 0) Size_MBs
,(SUM(mf.size) * 8 / 1024) / 1024 AS Size_GBs
FROM sys.master_files mf
INNER JOIN sys.databases d ON d.database_id = mf.database_id
WHERE d.database_id > 4
GROUP BY d.NAME
ORDER BY d.NAME
I have the above T-SQL script which lists all databases on an SQL Server instance along with their corresponding size in MBs & GBs.
What i'm struggling with is also to include a column for the number of tables in each database.
Does any one also know how i can improve the above script to also show the total numbers of tables in each listed database. Optionally, it would be nice to get also the number of rows in each table but this is not a big issue.
I'm targeting sql server 2005 and obove.

Not as a single script, you could obtain the requested result by
CREATE TABLE AllTables ([DB Name] sysname, [Schema Name] sysname, [Table Name] sysname)
DECLARE #SQL NVARCHAR(MAX)
SELECT #SQL = COALESCE(#SQL,'') + '
insert into AllTables
select ' + QUOTENAME(name,'''') + ' as [DB Name], [Table_Schema] as
[Table Schema], [Table_Name] as [Table Name] from ' +
QUOTENAME(Name) + '.INFORMATION_SCHEMA.Tables;' FROM sys.databases
ORDER BY name
EXECUTE(#SQL)
SELECT * FROM AllTables ORDER BY [DB Name],[SCHEMA NAME], [Table Name]
DROP TABLE AllTables
Reference:List of All Tables in All Databases

A wider report about all your databases could include stats over tables, views, procedures, triggers, amenities (xml, spatial indexes) and so far.
if object_ID('TempDB..#AllTables','U') IS NOT NULL drop table #AllTables
CREATE TABLE #AllTables (
[DB Name] sysname,
[Tables] int,
[Views] int,
[Procedures] int,
[Triggers] int,
[Full Text Catalogs] int,
[Xml Indexes] int,
[Spatial Indexes] int)
DECLARE #SQL NVARCHAR(MAX)
SELECT #SQL = COALESCE(#SQL,'') + 'USE ' + quotename(name) + '
insert into #AllTables
select ' + QUOTENAME(name,'''') + ' as [DB Name],
(select count(*) from ' + QUOTENAME(Name) + '.sys.tables),
(select count(*) from ' + QUOTENAME(Name) + '.sys.views),
(select count(*) from ' + QUOTENAME(Name) + '.sys.procedures),
(select count(*) from ' + QUOTENAME(Name) + '.sys.triggers),
(select count(*) from ' + QUOTENAME(Name) + '.sys.fulltext_catalogs),
(select count(*) from ' + QUOTENAME(Name) + '.sys.xml_indexes),
(select count(*) from ' + QUOTENAME(Name) + '.sys.spatial_indexes)
'
FROM sys.databases
ORDER BY name
-- print #SQL -- debug
EXECUTE(#SQL)
SELECT * FROM #AllTables
The provided solution, being far to be optimal, is easy to master and extend.
NOT OPTIMAL, just for sporadic report
based on (and credits to): http://blogs.lessthandot.com/index.php/DataMgmt/DataDesign/how-to-get-information-about-all-databas/

Related

SQL Server : relationship between columns in different tables

I would like to find a way to understand if there is a relationship between two columns present in two different tables.
For example in the table [Sales].[SalesOrderHeader], I have a column SalesOrderID and in another table [Person].[EmailAddress], there is BusinessEntityID.
How can I check to see if there is a table that creates a relationship between these 2 columns? Or how can I be sure that there is not a relationship between these 2 columns?
INFORMATION_SCHEMA is what you are looking for. You can see whether or not a given column is used in a constraint by executing
SELECT * FROM INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE WHERE TABLE_NAME = 'Person' AND COLUMN_NAME = 'BusinessEntityID'
You will have to do some additional work to focus on your specific solution, but this is where to start.
You could do one the following to find the tables that reference [Sales].[SalesOrderHeader]:
EXEC sp_fkeys #pktable_name = N'SalesOrderHeader',#pktable_owner = N'Sales';
I apologize before hand for what follows:
create table #rels (rel_name varchar(max), matches int) declare #sql varchar(max) = '' select #sql+= char(10) + 'insert into #rels select ''' tbla + '.' + col_a + '.' + tbl_b + '.' col_b ''' colrel, count(*) from ' + tbl_a + ' join ' + tbl_b + ' on cast(' + col_a + ' as varchar(max)) = cast(' + col_b + ' as varchar(max)) from ( select a.column_name col_a, object_name(a.object_id) tbl_a, b.column_name col_b, object_name(b.object_id) tbl_b from sys.columns a cross apply sys.columns b where a.column_name <> b.column_name where a.system_type_id = b.system_type_id ) cols exec (#sql) select * from #rels where matches > 0 order by matches desc drop table #rels

What is the T-SQL syntax to exclude a duplicate column in the output when joining 2 tables?

I am using SQL Server 2014 and I have the following T-SQL query which joins 2 tables:
SELECT a.*, b.* FROM TEMP a
INNER JOIN Extras b ON b.ResaID = a.ResaID
I would like to pull ALL the columns from TEMP and all the columns from "Extras" with the exception of the ResaID column as it is already included in a.* in the above query. Basically, I want to pull a.* + b.* (excluding b.ResaID).
I know I can write the query in the form:
Select a.*, b.column2, b.column3,...
but since b.* has got around 40 columns, is there a way to write the query in a more simplified way to exclude b.ResaID, rather than specify each of the columns in the "Extras" table?
Unfortunately, there is no such syntax. You could either use asterisks (*) and just ignore the duplicated column in your code, or explicitly list the columns you need.
You should create a view and select the columns you need from that view. Here is a script that will generate that view for you:
DECLARE #table1 nvarchar(20) = 'temp'
DECLARE #table1key nvarchar(20) = 'ResaID'
DECLARE #table2 nvarchar(20) = 'Extras'
DECLARE #table2key nvarchar(20) = 'ResaID'
DECLARE #viewname varchar(20) = 'v_myview'
DECLARE #sql varchar(max) = ''
SELECT #sql += '], a.[' + column_name
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = #table1
SELECT #sql += '], b.[' + column_name
FROM
(
SELECT column_name
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = #table2
EXCEPT
SELECT column_name
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = #table1
) x
SELECT
#sql = 'CREATE view ' +#viewname+ ' as SELECT '
+ STUFF(#sql, 1, 3, '') + '] FROM ['
+#table1+ '] a JOIN ['+ #table2
+'] b ON ' + 'a.' + #table1key + '=b.' + #table2key
EXEC(#sql)
You can simply solve this using a dynamic sql query.
DECLARE #V_SQL AS NVARCHAR(2000)='' --variable to store dynamic query
,#V_TAB1 AS NVARCHAR(200)='TEMP' --First Table
,#V_TAB2 AS NVARCHAR(200)='Extras' --Second Table
,#V_CONDITION AS NVARCHAR(2000)='A.ResaID = B.ResaID' --Conditions
SELECT #V_SQL = STUFF(
( SELECT ', '+TCOL_NAME
FROM
( SELECT 'A.'+S.NAME AS TCOL_NAME
FROM SYSCOLUMNS AS S
WHERE OBJECT_NAME(ID) = #V_TAB1
UNION ALL
SELECT 'B.'+S.NAME
FROM SYSCOLUMNS AS S
WHERE OBJECT_NAME(ID) = #V_TAB2
AND S.NAME NOT IN (SELECT S.NAME
FROM SYSCOLUMNS AS S
WHERE OBJECT_NAME(ID) = #V_TAB1)
) D
FOR XML PATH('')
),1,2,'')
EXECUTE ('SELECT '+#V_SQL+'
FROM '+#V_TAB1+' AS A
INNER JOIN '+#V_TAB2+' AS B ON '+#V_CONDITION+' ')

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)

Get a list of all columns that do not have only NULL values in SQL Server

I NEVER do complicated stuff in SQL - until now...
I have a database with over 2000 tables, each table has about 200 columns.
I need to get a list of all the columns in one of those tables that are populated at least 1 time.
I can get a list of all the columns like this:
SELECT [name] AS [Column name]
FROM syscolumns with (nolock)
WHERE id = (SELECT id FROM sysobjects where name like 'DOCSDB_TDCCINS')
But I need only the columns that are populated 1 or more times.
Any help would be appreciated.
Here is how I would do it, first run this:
SELECT 'SELECT '''+syscolumns.name+''' FROM '+sysobjects.name+' HAVING COUNT('+syscolumns.name+') > 0'
FROM syscolumns with (nolock)
JOIN sysobjects with (nolock) ON syscolumns.id = sysobjects.id
WHERE syscolumns.id = (SELECT id FROM sysobjects where name like 'Email')
Copy all the select statements and run them.
This will give you a list of the column names without nulls.
(nb I did not test because I don't have an SQL server available right now, so I could have a typo)
It may be also be useful to count the non-null instances, obviously 0 or not 0 was your initial question, and counting the instances versus exists not/exists will be slower.
select 'union select ''' + Column_Name + ''',count(*)'
+ ' from ' + table_name
+ ' where ' + column_name + ' is not null'
from
(
select * from information_schema.columns with (nolock)
where Is_Nullable = 'YES'
AND Table_Name like 'DOCSDB_TDCCINS'
) DD
Then remove the superfluous leading 'union' and run the query
A different idea is to create a dynamic unpivot for every table.
Declare #q NVarchar(MAX) = NULL
;With D AS (
SELECT TABLE_SCHEMA
, TABLE_NAME
, STUFF((SELECT ', ' + QUOTENAME(ci.COLUMN_NAME)
FROM INFORMATION_SCHEMA.COLUMNS ci
WHERE (ci.TABLE_NAME = c.TABLE_NAME)
AND (ci.TABLE_SCHEMA = c.TABLE_SCHEMA)
FOR XML PATH(''),TYPE).value('.','NVARCHAR(MAX)')
,1,2,'') AS _Cols
, STUFF((SELECT ', Count(' + QUOTENAME(ci.COLUMN_NAME) + ') '
+ QUOTENAME(ci.COLUMN_NAME)
FROM INFORMATION_SCHEMA.COLUMNS ci
WHERE (ci.TABLE_NAME = c.TABLE_NAME)
AND (ci.TABLE_SCHEMA = c.TABLE_SCHEMA)
FOR XML PATH(''),TYPE).value('.','NVARCHAR(MAX)')
,1,2,'') AS _ColsCount
FROM INFORMATION_SCHEMA.COLUMNS c
GROUP BY TABLE_SCHEMA, TABLE_NAME
)
SELECT #q = COALESCE(#q + ' UNION ALL ', '') + '
SELECT ''' + TABLE_SCHEMA + ''' _Schema, ''' + TABLE_NAME + ''' _Table, _Column
FROM (SELECT ' + _ColsCount + ' from ' + TABLE_SCHEMA + '.' + TABLE_NAME + ') x
UNPIVOT
(_Count FOR _Column IN (' + _Cols + ')) u
WHERE _Count > 0'
FROM D
exec sp_executesql #q
In the CTE _Cols returns the comma separated quoted name of the columns of the table, while _ColsCount returns the same list with the COUNT function, for example for a table of mine a row of D is
TABLE_SCHEMA | TABLE_NAME | _Cols | _ColsCount
------------- ----------------- ------------------------------ -----------------------------------------------------------------------------
dbo | AnnualInterests | [Product_ID], [Rate], [Term] | Count([Product_ID]) [Product_ID], Count([Rate]) [Rate], Count([Term]) [Term]
while the main query trasform this line in the UNPIVOT to return the columns in rows
SELECT 'dbo' _Schema, 'AnnualInterests' _Table, _Column
FROM (SELECT Count([Product_ID]) [Product_ID], Count([Term]) [Term]
, Count([Rate]) [Rate] from dbo.AnnualInterests) x
UNPIVOT
(_Count FOR _Column IN ([Product_ID], [Term], [Rate])
WHERE _Count > 0
using the string variable concatenation and sp_executesql to run the string complete the script.
Hope you can achieve this by a simple alteration on your code like
SELECT [name] AS [Column name]
FROM syscolumns with (nolock)
WHERE id = (SELECT id FROM sysobjects where name like 'DOCSDB_TDCCINS')
and (select count(*) from DOCSDB_TDCCINS)>0

Find table name in all objects of all databases

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.

Resources