How to count empty tables in database? - sql

Is there any way to count tables with no rows in my database with using T-SQL statement?

There you go... using a derived table.
SELECT * FROM
(
SELECT
[TableName] = so.name,
[RowCount] = MAX(si.rows)
FROM
sysobjects so,
sysindexes si
WHERE
so.xtype = 'U'
AND
si.id = OBJECT_ID(so.name)
GROUP BY
so.name
) sub
WHERE sub.[RowCount] = 0

I use the following:
SELECT t.NAME AS TableName, sum(p.rows) as RowCounts
FROM sys.tables t
INNER JOIN sys.indexes i
ON t.OBJECT_ID = i.object_id
INNER JOIN sys.partitions p
ON i.object_id = p.OBJECT_ID AND i.index_id = p.index_id
WHERE
i.name IS NULL AND i.index_id <= 1
GROUP BY
t.NAME, i.object_id, i.index_id, i.name
HAVING SUM(p.rows) = 0

from khtan # SQL Server Forums, this is used to drop all empty tables, maybe you could adapt it to output a count?
declare #name varchar(128), #sql nvarchar(2000), #i int
select #name = ''
while #name < (select max(name) from sysobjects where xtype = 'U')
begin
select #name = min(name) from sysobjects where xtype = 'U' and name > #name
select #sql = 'select #i = count(*) from [' + #name + ']'
exec sp_executesql #sql, N'#i int out', #i out
if #i = 0
begin
select #sql = 'drop table [' + #name + ']'
print #sql
-- unmask next to drop the table
-- exec (#sql)
end
end
I don't have SQLServer here but I could take a stab at it if you like.

Related

SQL Server how to find specific data across entire database

I have this script which finds all tables that contain data in column RGNCODE. I'm trying to amend this to find tables that contain a specific value for rgncode across all tables. So RGNCODE = 'UK'. Unsure where to add this in?
SELECT
sys.columns.name AS ColumnName,
tables.name AS TableName
FROM sys.columns
JOIN sys.tables ON sys.columns.object_id = tables.object_id
WHERE
sys.columns.name = 'rgncode' and
tables.name in (
SELECT [TableName] = so.name
FROM sysobjects so, sysindexes si
WHERE so.xtype = 'U' AND si.id = so.id
GROUP BY so.name
HAVING max(si.rows) > 0
)
A dynamic statement, using system catalog views, is an option here:
DECLARE #stm nvarchar(max) = N''
SELECT #stm = #stm +
CASE WHEN #stm = N'' THEN '' ELSE N'UNION ALL ' END +
N'SELECT ''' +
QUOTENAME(sch.[name]) + '.' + QUOTENAME(tab.[name]) + ''' AS TableName FROM ' +
QUOTENAME(sch.[name]) + '.' + QUOTENAME(tab.[name]) +
N' WHERE RGNCODE = ''UK'' HAVING COUNT(*) > 0 '
FROM sys.columns col
JOIN sys.tables tab ON col.object_id = tab.object_id
JOIN sys.schemas sch ON tab.schema_id = sch.schema_id
WHERE col.[name] = 'RGNCODE'
PRINT #stm
EXEC sp_executesql #stm
I think the following cursor will help you:
CREATE TABLE ##DataTable
(TblName VARCHAR(100),RowNum INT)
GO
DECLARE #TableName AS VARCHAR(200)
DECLARE #SQLText AS nVARCHAR(MAX)
DECLARE #TableCount AS INT
DECLARE TableDect CURSOR
FOR
SELECT
tables.name AS TableName
FROM
sys.columns
JOIN sys.tables ON
sys.columns.object_id = tables.object_id
WHERE
sys.columns.name = 'rgncode' and tables.name in (
SELECT
[TableName] = so.name
FROM
sysobjects so,
sysindexes si
WHERE
so.xtype = 'U'
AND
si.id = so.id
GROUP BY
so.name
HAVING max(si.rows) >0 )
OPEN TableDect
FETCH NEXT FROM TableDect INTO #TableName
WHILE ##FETCH_STATUS = 0
BEGIN
SET #SQLText = N'SELECT #NumberOUT=COUNT(*) FROM ' + QUOTENAME(#TableName) + ' WHERE rgncode=''UK'''
SET #TableCount = 0
EXECUTE sp_executesql #SQLText ,N'#NumberOUT nvarchar(25) OUTPUT' ,#NumberOUT=#TableCount OUTPUT
INSERT INTO ##DataTable values(#TableName,#TableCount)
FETCH NEXT FROM TableDect INTO #TableName
END
CLOSE TableDect;
DEALLOCATE TableDect
SELECT * FROM ##DataTable

how to dynamically select database inside stored procedure?

Create PROC spABC
#dbname varchar(20)
As
Use [#dbname] /*NOT ALLOWED*/
BEGIN
...
END
I was able to achieve my solution in the following way. The script was run inside BEGIN...END
DECLARE #sql NVARCHAR(max)
SET #sql = N'Use ' + #dbName +N'
Select DISTINCT S.name Name,
S.create_date DOC,
S.modify_date DOM ,
P.rows ROWCNT,
MAX(C.column_id) COLCNT,
SUM(a.total_pages) * 8 AS TotalSpaceKB,
SUM(a.used_pages) * 8 AS UsedSpaceKB
From sys.tables AS S
LEFT JOIN sys.partitions P
ON S.object_id = P.object_id
LEFT JOIN sys.columns C
ON S.object_id = C.object_id
INNER JOIN sys.allocation_units a
ON p.partition_id = a.container_id
Group BY S.name , S.create_date , S.modify_date , P.rows '
EXEC sp_executesql #sql

Query to find Size for each table By Filtering Rows

The Following Code will display the Size of each table in database
USE DatabaseName
GO
CREATE TABLE #temp (
table_name SYSNAME
, row_count INT
, reserved_size VARCHAR(50)
, data_size VARCHAR(50)
, index_size VARCHAR(50)
, unused_size VARCHAR(50)
)
SET NOCOUNT ON
INSERT #temp
EXEC sp_MSforeachtable 'sp_spaceused ''?'''
SELECT a.table_name
, a.row_count
, COUNT(*) AS col_count
, a.data_size
FROM #temp a
INNER JOIN INFORMATION_SCHEMA.columns b ON a.table_name COLLATE database_default
= b.table_name COLLATE database_default
GROUP BY a.table_name
, a.row_count
, a.data_size
ORDER BY CAST(REPLACE(a.data_size, ' KB', '') AS INTEGER) DESC
DROP TABLE #temp
Is there any way to Find the Space of All table by filtering the Row.
Like I have Foreign Key Company ID In All Table would it be possible if i want to know the space Occupied by Company
---Example ---
Purchase Table :
P_ID P_Description P_Price P_CompanyID
------------------------------------------
1 Mobile 100 1
2 Laptop 2100 1
3 Table 50 2
Sale table:
S_ID s_Description S_Price S_CompanyID
------------------------------------------
1 Mobile 110 1
2 Laptop 2200 1
3 Table 100 2
OutPut table:
Table Size Company
---------------------------------
Purchase 1.5MB 1
Sale 1.5MB 1
Purchase 1MB 2
Sale 1MB 2
I have Found the solution as per my Requirement. Thanks to Devart Help.
DECLARE #tblNAME NVARCHAR(50) = ''
DECLARE #colNAME NVARCHAR(50) = ''
DECLARE #SQL NVARCHAR(MAX) = ''
DECLARE CUR CURSOR FOR
SELECT NAME
FROM SYS.TABLES
WHERE TYPE = 'U'
AND SCHEMA_ID = 1
AND name NOT LIKE 'tt_%'
OPEN CUR
FETCH NEXT FROM CUR INTO #tblNAME
WHILE ##FETCH_STATUS = 0
BEGIN
SELECT #colNAME= c.name
FROM sys.columns c,sys.objects o
WHERE c.[object_id] = o.[object_id]
AND c.name like '%_CompanyID' And o.name=#tblNAME
if #colNAME is null or #colNAME =''
begin
FETCH NEXT FROM CUR INTO #tblNAME
end
Else
Begin
-- PRINT #tblNAME
--Print '---'+ #colNAME
SELECT #SQL += '
IF OBJECT_ID(''tt_' + o.name + ''') IS NOT NULL
DROP TABLE [tt_' + o.name + ']
SELECT *
INTO [tt_' + o.name + ']
FROM ' + QUOTENAME(SCHEMA_NAME(o.[schema_id])) + '.' + QUOTENAME(o.name) + '
WHERE '+#colNAME+' =10' -- your condition
FROM sys.objects o
WHERE o.[type] = 'U'
AND o.name NOT LIKE 'tt_%'
AND o.name LIKE #tblNAME
AND o.is_ms_shipped = 0
AND EXISTS(
SELECT *
FROM sys.columns c
WHERE c.[object_id] = o.[object_id]
AND c.name like '%_CompanyID' -- your column
)
Set #colNAME=null
FETCH NEXT FROM CUR INTO #tblNAME
end
END
CLOSE CUR
DEALLOCATE CUR
Print #SQL
EXEC sys.sp_executesql #SQL
SELECT REPLACE(o.name, 'tt_', '') as TableName, t.Size, t.Total_Rows, '1' as IsClient
FROM sys.objects o
JOIN (
SELECT
i.[object_id]
, size = SUM(a.total_pages) * 8. / 1024
, total_rows = SUM(CASE WHEN i.index_id IN (0, 1) AND a.[type] = 1 THEN p.[rows] END)
FROM sys.indexes i
JOIN sys.partitions p ON i.[object_id] = p.[object_id] AND i.index_id = p.index_id
JOIN sys.allocation_units a ON p.[partition_id] = a.container_id
GROUP BY i.[object_id]
) t ON o.[object_id] = t.[object_id]
WHERE o.name LIKE 'tt_%'
AND o.is_ms_shipped = 0
AND o.[type] = 'U'
ORDER BY t.size DESC
SET #SQL = ''
SELECT #SQL += '
DROP TABLE [' + o.name + ']'
FROM sys.objects o
WHERE o.[type] = 'U'
AND o.name LIKE 'tt_%'
AND o.is_ms_shipped = 0
EXEC sys.sp_executesql #SQL

SQL Server 2014 Dynamic SQL

Please take a look at the code and help me on the last part, --put all together = fail !!!
I wanted to generate a string for executing sp_executesql but I'm getting an error at the end. I also tried open cursor but it error out too.
Basically I'm trying to get actual row count per column per table for all tables
because general rowcount want give you if new column added and populated.
USE AdventureWorks2014
GO
-- Create view to hold the dataset
Alter view vColumnSchema
AS
with myColumnName
As
(
Select TOP (100) PERCENT
GetDate() As create_date,
##SERVERNAME As Server_Name,
DB_Name() AS database_name,
c.[object_id],
s.name AS [schema_name],
t.name as table_name,
c.name as column_name,
p.rows AS NUM_ROWS,
c.[precision]
from sys.tables as t
INNER JOIN sys.columns as c with(nolock) on t.[object_id] = c.[object_id]
INNER JOIN sys.indexes AS i ON t.object_id = i.object_id
INNER JOIN sys.partitions AS p ON i.object_id = p.object_id AND i.index_id = p.index_id
INNER JOIN sys.schemas AS s ON s.schema_id = t.schema_id
WHERE t.name NOT LIKE 'dt%'
AND i.object_id > 255
AND i.index_id <= 1
And s.name is not null
Order by s.name,
t.name
)
Select Top 100 percent
create_date,
Server_Name,
database_name,
[schema_name],
table_name,
column_name,
NUM_ROWS,
case when precision = 0 then
'Select Count('+column_name+')'+' from ' +[schema_name]+'.'+table_name+ ' where '+column_name+'<> '''' '
else
'Select Count(' +column_name+')'+' from ' +[schema_name]+ '.'+table_name+' where '+column_name+'> 0'
END as ColumnCount,
case when precision = 0
then ' <> '''' '
Else '> 0'
END As WhereClause
from myColumnName
Order by [schema_name],
table_name
GO
select * from vColumnSchema
where table_name = 'ProductCostHistory'
go
select * from Production.ProductCostHistory -- 395 records
--pick one record and test it = pass
Select Count(EndDate) from Production.ProductCostHistory where EndDate<> '' --200 records
GO
--test = pass on both whereClause
Declare #Column_name nvarchar(50) = 'EndDate'
Declare #Schema_Name nvarchar(20) = 'Production'
declare #table_name nvarchar(50) = 'ProductCostHistory'
declare #whereClause nvarchar(5) = '<> '''' '
declare #sqltext nvarchar(max) ='
select count('+#Column_name+') as ColumnCount from ' +#Schema_Name+'.'+#table_name+' where '+#Column_name+' '+#WhereClause+'
'
EXECUTE sp_executesql #sqltext
GO
--examine each column = pass
Declare #Column_name nvarchar(50) = 'select Column_name from vColumnSchema'
EXECUTE sp_executesql #Column_name
GO
Declare #schema_name nvarchar(50) = 'select schema_name from vColumnSchema'
EXECUTE sp_executesql #schema_name
GO
declare #table_name nvarchar(50) = 'select table_name from vColumnSchema'
EXECUTE sp_executesql #table_name
GO
declare #WhereClause nvarchar(50) = 'select WhereClause from vColumnSchema'
EXECUTE sp_executesql #WhereClause
GO
--put all together = fail !!!
declare #Column_name nvarchar(50) = 'select Column_name from vColumnSchema'
declare #schema_name nvarchar(50) = 'select schema_name from vColumnSchema'
declare #table_name nvarchar(50) = 'select table_name from vColumnSchema'
declare #WhereClause nvarchar(5) = 'select WhereClause from vColumnSchema';
declare #sqltext nvarchar(max) ='
select count('+#Column_name+') as ColumnCount from ' +#Schema_Name+'.'+#table_name+' where '+#Column_name+' '+#WhereClause+'
'
EXECUTE sp_executesql #sqltext
go
If you want the number of rows per column per table:
DECLARE #sql NVARCHAR(MAX) = '';
SELECT #sql = #sql +
N'SELECT '''
+ t.name + ''' AS TableName, '''
+ c.name + ''' AS ColName, COUNT(' + QUOTENAME(c.name) + ') AS [RowCount] FROM '
+ QUOTENAME(t.name) + ' UNION ALL' + CHAR(10)
FROM sys.tables t
INNER JOIN sys.columns c
ON c.object_id = t.object_id
WHERE
t.type = 'U'
AND c.system_type_id <> 35
SELECT #sql = LEFT(#sql, LEN(#sql) - 11)
PRINT #sql
EXECUTE sp_executesql #sql
Not Sure what your end game is But this might help and does not use dynamic sql ...
You can put the number of columns in your original query without a CTE
This puts the col count in the original select
Select TOP (100) PERCENT
GetDate() As create_date,
##SERVERNAME As Server_Name,
DB_Name() AS database_name,
c.[object_id],
s.name AS [schema_name],
t.name as table_name,
c.name as column_name,
p.rows AS NUM_ROWS,
c.[precision] ,
(Select COUNT(c2.object_id)
FROM sys.columns c2
INNER JOIN sys.tables t2 ON t2.object_id = c2.object_id
WHERE t2.object_id = t.object_id
GROUP BY c2.object_id) as ColCountThisTbl
from sys.tables as t
INNER JOIN sys.columns as c with(nolock) on t.[object_id] = c.[object_id]
INNER JOIN sys.indexes AS i ON t.object_id = i.object_id
INNER JOIN sys.partitions AS p ON i.object_id = p.object_id AND i.index_id = p.index_id
INNER JOIN sys.schemas AS s ON s.schema_id = t.schema_id
WHERE t.name NOT LIKE 'dt%'
AND i.object_id > 255
AND i.index_id <= 1
And s.name is not null
Order by s.name,
t.name `enter code here`

Drop default constraint in SQL Server on many columns

For SQL Server 2008 R2 I want to remove default constraints for date columns that allow null and the constraint contains 1899. And I want a script that can tested and then executed in live. I don't wan't to fiddle with this in live environment. Another reason for a script is that there is several databases with the same scheme
With help from Google I have the following script that list columns
SELECT tables.name, all_columns.name, all_columns.is_nullable, default_constraints.name, default_constraints.definition
FROM
sys.all_columns
INNER JOIN
sys.tables
ON all_columns.object_id = tables.object_id
INNER JOIN
sys.schemas
ON tables.schema_id = schemas.schema_id
INNER JOIN
sys.default_constraints
ON all_columns.default_object_id = default_constraints.object_id
WHERE
schemas.name = 'dbo'
and default_constraints.definition like '%1899%'
and all_columns.is_nullable = 1
order by tables.name, all_columns.name, default_constraints.name
Now this list over hundred columns. The next script do what I want for the column CargoPool.Created. But how can I iterate all rows created from my first script ?
DECLARE #tableName VARCHAR(MAX) = 'CargoPool'
DECLARE #columnName VARCHAR(MAX) = 'Created'
DECLARE #ConstraintName nvarchar(200)
SELECT #ConstraintName = Name
FROM SYS.DEFAULT_CONSTRAINTS
WHERE PARENT_OBJECT_ID = OBJECT_ID(#tableName)
AND PARENT_COLUMN_ID = (
SELECT column_id FROM sys.columns
WHERE NAME = #columnName AND object_id = OBJECT_ID(#tableName))
IF #ConstraintName IS NOT NULL
EXEC('ALTER TABLE '+#tableName+' DROP CONSTRAINT ' + #ConstraintName)
If you want to drop all the constraints from your first query, you can build up a dynamic SQL with the results of that query and then execute it:
DECLARE #sql AS NVARCHAR(MAX) = N''
SELECT #sql = #sql + N'ALTER TABLE '
+ QUOTENAME(schemas.name) + N'.' + QUOTENAME(tables.name)
+ N' DROP CONSTRAINT ' + QUOTENAME(default_constraints.name) + N'; '
FROM
sys.all_columns
INNER JOIN
sys.tables
ON all_columns.object_id = tables.object_id
INNER JOIN
sys.schemas
ON tables.schema_id = schemas.schema_id
INNER JOIN
sys.default_constraints
ON all_columns.default_object_id = default_constraints.object_id
WHERE
schemas.name = N'dbo'
and default_constraints.definition like N'%1899%'
and all_columns.is_nullable = 1
order by tables.name, all_columns.name, default_constraints.name
exec sp_executesql #sql;