Iterate through all DBs - Get constraints in all tables - sql-server

I'm trying to iterate through all databases by listing all table constraints. I've achieved the following:
DECLARE #sql nvarchar(max) = ''
SET #sql =
'
USE ?
select con.[name] as constraint_name,
schema_name(t.schema_id) + ''.'' + t.[name] as [table],
col.[name] as column_name,
con.[definition],
case when con.is_disabled = 0
then ''Active''
else ''Disabled''
end as [status]
from sys.check_constraints con
left outer join sys.objects t
on con.parent_object_id = t.object_id
left outer join sys.all_columns col
on con.parent_column_id = col.column_id
and con.parent_object_id = col.object_id
order by con.name
'
PRINT #sql
EXEC sp_MSforeachdb #sql
I would like to have the query UNION all of my results in one clean select.
Can anyone help?
Using SQL Server 2016.

One way is to insert the intermediate results into a temp table. Below is an example that also includes the database name in the results.
CREATE TABLE #results (
[database_name] sysname
,[constraint_name] nvarchar(128)
,[table] nvarchar(257)
,[column_name] nvarchar(128)
,[definition] nvarchar(max)
,[status] varchar(8)
);
DECLARE #sql nvarchar(max) = ''
SET #sql =
N'
USE [?];
INSERT INTO #results
select
N''?'' as database_name,
con.[name] as constraint_name,
schema_name(t.schema_id) + ''.'' + t.[name] as [table],
col.[name] as column_name,
con.[definition],
case when con.is_disabled = 0
then ''Active''
else ''Disabled''
end as [status]
from sys.check_constraints con
left outer join sys.objects t
on con.parent_object_id = t.object_id
left outer join sys.all_columns col
on con.parent_column_id = col.column_id
and con.parent_object_id = col.object_id;
';
PRINT #sql;
EXEC sp_MSforeachdb #sql;
SELECT * FROM #results;

Related

List of all tables across all databases with row count of each table

I want to get the list of ALL tables across ALL databases in a server along with row count of EACH table.
For now, I have developed a code that gives the list of all tables with all databases. However, I need help in adding row count of each of these tables.
CREATE PROCEDURE [dbo].[List_of_tables_in_All_Databases]
(#clean BIT = 1,
#debugEnabled BIT = 0)
AS
BEGIN
DECLARE #message NVARCHAR(MAX)
DECLARE #procName NVARCHAR(250) = object_name(##procid);
DECLARE #processingProcStart DATETIME = GETDATE()
DECLARE #processingprocTime INT = 0
SET #message = 'List_of_tables_in_All_Databases START: ' + CONVERT(VARCHAR(23), GETDATE(), 121);
EXEC [dbo].[usp_KREOInsertLog] #type = 'INFO', #source = 'Analysis', #storedProcedure = #procName, #debugLevel = 1, #message = #message, #show = #debugEnabled
IF OBJECT_ID (N'tempdb.dbo.#AllTables ') IS NOT NULL
DROP TABLE #AllTables
SET NOCOUNT ON
CREATE TABLE #AllTables
(
ServerName NVARCHAR(200),
DBName NVARCHAR(200),
SchemaName NVARCHAR(200),
TableName NVARCHAR(200),
[RowCount] INT
)
DECLARE #SearchSvr NVARCHAR(200),
#SearchDB NVARCHAR(200),
#SearchS NVARCHAR(200),
#SearchTbl NVARCHAR(200),
#SQL NVARCHAR(4000)
SET #SearchSvr = NULL --Search for Servers, NULL for all Servers
SET #SearchDB = NULL --Search for DB, NULL for all Databases
SET #SearchS = 'dbo' --Search for Schemas, NULL for all Schemas
SET #SearchTbl = NULL --Search for Tables, NULL for all Tables
SELECT #SQL = 'SELECT ##SERVERNAME
,''?''
,s.name
,t.name
FROM sys.tables t
JOIN sys.schemas s on t.schema_id=s.schema_id
WHERE ##SERVERNAME LIKE ''%' + ISNULL(#SearchSvr, '') + '%''
AND ''?'' LIKE ''%' + ISNULL(#SearchDB, '') + '%''
AND s.name LIKE ''%' + ISNULL(#SearchS, '') + '%''
AND t.name LIKE ''%' + ISNULL(#SearchTbl, '') + '%''
AND ''?'' NOT IN (''master'',''model'',''msdb'',''tempdb'',''SSISDB'')
'
-- Remove the '--' from the last statement in the WHERE clause to exclude system tables
INSERT INTO #AllTables (ServerName, DBName, SchemaName, TableName)
EXEC sp_MSforeachdb #SQL
SELECT * FROM #AllTables
Can someone help with writing the code that gives the row counts for these tables?
There's a quick way to get row counts using SQL Server metadata. You could add this into your query in #SQL:
SELECT [Rows] = SUM(row_count)
FROM sys.dm_db_partition_stats
WHERE object_id=#YourObjectId
AND (index_id=0 or index_id=1);
I believe that would make the full #SQL as follows. Untested, but should at least be pretty close:
SELECT #SQL = 'SELECT ##SERVERNAME
,''?''
,s.name
,t.name
,SUM(p.row_count) as [rows]
FROM sys.tables t
JOIN sys.schemas s on t.schema_id=s.schema_id
LEFT JOIN sys.dm_db_partition_stats p
ON p.object_id = t.object_id
and (p.index_id = 0 or p.index_id = 1)
WHERE ##SERVERNAME LIKE ''%' + ISNULL(#SearchSvr, '') + '%''
AND ''?'' LIKE ''%' + ISNULL(#SearchDB, '') + '%''
AND s.name LIKE ''%' + ISNULL(#SearchS, '') + '%''
AND t.name LIKE ''%' + ISNULL(#SearchTbl, '') + '%''
AND ''?'' NOT IN (''master'',''model'',''msdb'',''tempdb'',''SSISDB'')
GROUP BY s.name, t.name
'
You could also show the size in MB along with that info, I always use this query for that
select t.NAME AS TableName,
i.name as indexName,
sum(p.rows) / count(a.total_pages) as RowCounts,
count(a.total_pages) as page_count,
sum(a.total_pages) as TotalPages,
sum(a.used_pages) as UsedPages,
sum(a.data_pages) as DataPages,
(sum(a.total_pages) * 8) / 1024 as TotalSpaceMB,
(sum(a.used_pages) * 8) / 1024 as UsedSpaceMB,
(sum(a.data_pages) * 8) / 1024 as DataSpaceMB
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
inner join sys.allocation_units a ON p.partition_id = a.container_id
where t.NAME NOT LIKE 'dt%'
and i.OBJECT_ID > 255
and i.index_id <= 1
group by t.NAME, i.object_id, i.index_id, i.name
order by sum(p.rows) / count(a.total_pages) DESC
Complete example combining the work done by Jeff and the original question. I also fixed an issue where database names have '.'s in them, generated the pivot columns:
SET NOCOUNT ON
IF OBJECT_ID('tempdb..#ServerTablesPivot') IS NOT NULL
TRUNCATE TABLE #ServerTablesPivot
ELSE
CREATE TABLE #ServerTablesPivot
(
DBName NVARCHAR(200),
SchemaName NVARCHAR(200),
TableName NVARCHAR(200),
[RowCount] INT
)
DECLARE #SearchSvr NVARCHAR(200),
#SearchDB NVARCHAR(200),
#SearchS NVARCHAR(200),
#SearchTbl NVARCHAR(200),
#SQL NVARCHAR(4000)
SET #SearchDB = 'UAT.Tenant00' --Search for DB, NULL for all Databases
SET #SearchS = 'dbo' --Search for Schemas, NULL for all Schemas
SET #SearchTbl = NULL --Search for Tables, NULL for all Tables
SELECT #SQL = 'USE [?]; SELECT
''?''
,s.name
,t.name
,SUM(p.rows) as [rows]
FROM sys.tables t
INNER JOIN sys.partitions p
ON p.OBJECT_ID = t.OBJECT_ID
INNER JOIN sys.schemas s
ON t.schema_id = s.schema_id
WHERE t.is_ms_shipped = 0 AND p.index_id IN (1,0)
AND ''?'' LIKE ''%' + ISNULL(#SearchDB, '') + '%''
AND s.name LIKE ''%' + ISNULL(#SearchS, '') + '%''
AND t.name LIKE ''%' + ISNULL(#SearchTbl, '') + '%''
AND ''?'' NOT IN (''master'',''model'',''msdb'',''tempdb'',''SSISDB'')
GROUP BY s.name,t.name'
-- Remove the '--' from the last statement in the WHERE clause to exclude system tables
INSERT INTO #ServerTablesPivot (DBName, SchemaName, TableName, [RowCount])
EXEC sp_MSforeachdb #SQL
--SELECT * FROM #ServerTablesPivot
--Declare necessary variables
DECLARE #SQLQuery AS NVARCHAR(MAX)
DECLARE #PivotColumns AS NVARCHAR(MAX)
--Get unique values of pivot column
SELECT #PivotColumns= COALESCE(#PivotColumns + ',','') + QUOTENAME([DBName])
FROM (SELECT DISTINCT [DBName] FROM #ServerTablesPivot) AS PivotExample
--SELECT #PivotColumns
--Create the dynamic query with all the values for
--pivot column at runtime
SET #SQLQuery =
N' -- Your pivoted result comes here
SELECT [TableName], ' + #PivotColumns + '
FROM
(
-- Source table should in a inner query
SELECT [DbName], [TableName], [RowCount]
FROM #ServerTablesPivot
)AS P
PIVOT
(
-- Select the values from derived table P
MIN([RowCount])
FOR [DbName] IN (' + #PivotColumns + ')
)AS PVTTable'
--SELECT #SQLQuery
--Execute dynamic query
EXEC sp_executesql #SQLQuery

I have this stored procedure and I want to revise it to be to rebuild more than one index in SQL

I have this stored procedure and I want to revise it to be to rebuild more than one index.
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [Landing].[usp_IndexDisableRebuild]
(#Schema_Name VARCHAR(256),
#Table_Name VARCHAR(256),
#Task_Name VARCHAR(256))
AS
-- Set to get the dynamic Script for
DECLARE #sql VARCHAR(MAX)
SET #sql = (SELECT 'ALTER INDEX ' + QUOTENAME(I.name) + ' ON ' + QUOTENAME(SCHEMA_NAME(T.schema_id))+'.'+ QUOTENAME(T.name) + #Task_Name FROM sys.indexes I INNER JOIN sys.tables T ON I.object_id = T.object_id INNER Join sys.schemas s ON s.schema_id = t.schema_id WHERE I.type_desc = 'NONCLUSTERED' AND I.name IS NOT NULL --AND I.is_disabled = 0 AND t.name = #Table_Name AND s.name = #Schema_Name )
-- Execute the dynamic SQL
EXEC (#sql)
I agree with the comments that you should consider using Ola Hallengren's SQL Server Maintenance Solution.
That being said, you could change your proc like to example below. In addition to correcting the subquery error, this uses the proper data types. Not sure what you want to do with #Task_Name so I just appended the value as a comment.
ALTER PROCEDURE [Landing].[usp_IndexDisableRebuild]
#Schema_Name sysname,
#Table_Name sysname,
#Task_Name VARCHAR(256)
AS
DECLARE #SQL nvarchar(MAX);
SET #SQL = (
SELECT 'ALTER INDEX ' + QUOTENAME(I.name)
+ ' ON ' + QUOTENAME(SCHEMA_NAME(T.schema_id))+'.'+ QUOTENAME(T.name) + ' REBUILD;
--' + #Task_Name + '
'
FROM sys.indexes I
INNER JOIN sys.tables T ON I.object_id = T.object_id
INNER Join sys.schemas s ON s.schema_id = t.schema_id
WHERE I.type_desc = 'NONCLUSTERED'
AND I.name IS NOT NULL
AND I.is_disabled = 0
AND t.name = #Table_Name
AND s.name = #Schema_Name
FOR XML PATH(''), TYPE).value('.','nvarchar(MAX)');
--PRINT #SQL;
EXECUTE sp_executesql #SQL;
GO

List all tables used in a SQL statement

Currently i have to create a list of all tables & schemes used in several (terribly) long SQL statements.
Of course i could go manually through the SQL statements and write down every table used in a JOIN, Subselect and so on.
But i'd be curious if there is any easier way to do it. maybe with a "simple" SQL statement, but i have no clue how to do it.
Why am i asking? I'd have to do this for about 50 SQL-Unload-Statements, where all of them use between 30 and 70 tables. I guess you can imagine this quite boring work
Thanks in advance for any input & hints!
Have a read here: How can i get the list of tables in the stored procedure
;WITH stored_procedures AS (
SELECT
o.name AS proc_name, oo.name AS table_name,
ROW_NUMBER() OVER(partition by o.name,oo.name ORDER BY o.name,oo.name) AS row
FROM sysdepends d
INNER JOIN sysobjects o ON o.id=d.id
INNER JOIN sysobjects oo ON oo.id=d.depid
WHERE o.xtype = 'P')
SELECT proc_name, table_name FROM stored_procedures
WHERE row = 1
ORDER BY proc_name,table_name
All credit to the OP of the code above in the thread above.
I will post this answer & mark it as solved, as it was the best and easiest way to solve my issue.
Hint was in a comment by #whereisSQL (thanks a lot!)
Seems like it was already asked in this thread, but i didn't find it:
https://dba.stackexchange.com/questions/121346/need-to-get-identify-all-tables-and-columns-in-a-sql-query/121355#121355
There is an online "get table column" tool to list the tables of a SQL statement here:
http://107.170.101.241:8080/getTableColumn/
It lists all tables and additionally columns used in the statement! Perfect solution in my case.
This may help. Using DMVs
IF EXISTS (
SELECT *
FROM sys.objects
WHERE object_id = OBJECT_ID(N'[dbo].[sp_dependsobj]')
AND type IN (
N'P'
,N'PC'
)
)
DROP PROCEDURE [dbo].[sp_dependsobj]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE PROCEDURE [dbo].[sp_dependsobj] (#Objname NVARCHAR(2000))
AS
BEGIN
SET NOCOUNT ON
DECLARE #ObjID INTEGER
DECLARE #ObjType VARCHAR(100)
DECLARE #RowCount INTEGER = 0
SELECT #ObjID = OBJECT_ID(#Objname)
SELECT #ObjType = TYPE
FROM sys.objects
WHERE object_id = #ObjID
DECLARE #RefObjects AS TABLE (
[Object_name] SYSNAME
,[Type] VARCHAR(255)
,referenced_entity_name SYSNAME
,Column_name SYSNAME NULL
,referenced_entity_type VARCHAR(255)
)
DECLARE #FoundIn AS TABLE (
[Object_name] SYSNAME
,[Found In] SYSNAME
,[Type] VARCHAR(255)
)
DECLARE #SQLStr VARCHAR(MAX)
SET #SQLStr = '
WITH CTE_Objects
AS
(
SELECT o.NAME referencing_entity_name
,o.type_desc referencing_object_type
,sed.referenced_entity_name
,refobj.referenced_minor_name
,obj.type_desc
,obj.object_id
FROM sys.sql_expression_dependencies sed
INNER JOIN sys.objects o ON sed.referencing_id = o.[object_id]
INNER JOIN sys.objects obj ON sed.referenced_entity_name = obj.name
INNER JOIN sys.dm_sql_referenced_entities(''dbo.' + #Objname + ''', ''OBJECT'') refobj ON
refobj.referenced_id = sed.referenced_id
WHERE o.NAME = ''' + #Objname + '''
UNION
SELECT ''' + #Objname + ''', (SELECT type_desc from sys.objects where name = ''' + #Objname + '''), referenced_entity_name, NULL, obj.type_desc
,obj.object_id
FROM sys.dm_sql_referenced_entities (''dbo.' + '' + #Objname +
''', ''OBJECT'') refObj INNER JOIN sys.objects obj
ON refObj.referenced_entity_name = obj.name
)
SELECT CTE.referencing_entity_name Object_name, CTE.referencing_object_type Type, CTE.referenced_entity_name, CTE.referenced_minor_name Column_name, CTE.type_desc referenced_entity_type
FROM CTE_Objects CTE LEFT JOIN sys.columns cl ON
cte.object_id = cl.object_id AND cte.referenced_minor_name = cl.name
Order by cte.referencing_entity_name, CASE WHEN cte.referencing_entity_name IS NULL THEN 0 ELSE cl.column_id END
'
INSERT INTO #RefObjects (
[Object_name]
,[Type]
,referenced_entity_name
,Column_name
,referenced_entity_type
)
EXEC (#SQLStr)
SET #RowCount = ##ROWCOUNT
IF #RowCount > 0
BEGIN
SELECT *
FROM #RefObjects
END
SET #SQLStr = '
SELECT DISTINCT [Object Name] = o.NAME
,[Found In] = sp.NAME
,sp.type_desc Type
FROM sys.objects o
INNER JOIN sys.sql_expression_dependencies sd ON o.object_id = sd.referenced_id
INNER JOIN sys.objects sp ON sd.referencing_id = sp.object_id
WHERE o.NAME = ''' + #Objname + '''
UNION
SELECT ''' + #Objname + ''', referencing_entity_name, (SELECT type_desc from sys.objects where name = referencing_entity_name)
FROM sys.dm_sql_referencing_entities (''dbo.' + '' + #Objname + ''', ''OBJECT'');
'
INSERT INTO #FoundIn (
[Object_name]
,[Found In]
,[Type]
)
EXEC (#SQLStr)
SET #RowCount = ##ROWCOUNT
IF #RowCount > 0
BEGIN
SELECT *
FROM #FoundIn
END
IF NOT EXISTS (
SELECT 1
FROM #RefObjects
)
AND NOT EXISTS (
SELECT 1
FROM #FoundIn
)
BEGIN
PRINT 'Object does not reference any object, and no objects reference it.'
END
SET NOCOUNT OFF
END
GO
The question is old, but here is a regex for those that want the tables used in SQL statement (From/join).
I created it specially for my case, but it may be adapt and useful for others:
(from|join)[ ]{1,}[^.\n\ ]+?(?=(.))[.].*?(?=( |\n))

loop through all tables and delete records

I'm new to MsSql and I'm not sure if this can be done but I figured I'd ask before I want on my way with the current process..
I need to create a script that loops through all tables in a database and deletes the rows where CorporationId = "xxx". There are a few tables that do not have this column, but of my ~50 tables, only 1 or two do not.
I can individually delete the records in the table with this:
USE MyDatabase
DECLARE #CorporationId UniqueIdentifier
DECLARE #TokenId UniqueIdentifier
DECLARE #CompanyCode nChar(3)
SET #CorporationId = '52D3AEFE-8EBD-4669-8096-4596FE83BB36'
print 'Starting Web.GasOrder'
DELETE FROM Web.GasOrder
WHERE CorporationId = #CorporationId
print 'Starting Web.GasOrderNumber'
DELETE FROM Web.GasOrderNumber
WHERE CorporationId = #CorporationId
etc..
But this is getting tedious creating one for each table.
Of course, some of the tables have relationships on them.
Is there an easy way to do this or do I need to do it manually for each table?
UPDATE
Most of the options that I have tried run into problems with relationships and give me an error.
sp_MSForEachTable is an undocumented stored procedure which will run a command for each table in the database:
USE MyDatabase
DECLARE #CorporationId VARCHAR(50)
SET #CorporationId = '52D3AEFE-8EBD-4669-8096-4596FE83BB36'
DECLARE #Sql VARCHAR(MAX)
SET #Sql = '
IF COL_LENGTH(''?'',''CorporationId'') IS NOT NULL
BEGIN
DELETE FROM Web.?
WHERE CorporationId = ''' + #CorporationId + '''
END
'
EXEC sp_MSForEachTable #Sql
Here's another one... could easily be changed to a stored procedure...
Declare #corpID Nvarchar(256)
Set #corpID = 'xxx'
If Object_ID('tempdb..#tables') Is Not Null Drop Table #tables
Create Table #tables (tID Int, SchemaName Nvarchar(256), TableName Nvarchar(256))
Insert #tables
Select Row_Number() Over (Order By s.name, so.name), s.name, so.name
From sysobjects so
Join sys.schemas s
On so.uid = s.schema_id
Join syscolumns sc
On so.id = sc.id
Where so.xtype = 'u'
And sc.name = 'CorporationId'
Declare #SQL Nvarchar(Max),
#schema Nvarchar(256),
#table Nvarchar(256),
#iter Int = 1
While Exists (Select 1
From #tables)
Begin
Select #schema = SchemaName,
#table = TableName
From #tables
Where tID = #iter
If Exists (Select 1
From sysobjects o
Join sys.schemas s1
On o.uid = s1.schema_id
Join sysforeignkeys fk
On o.id = fk.rkeyid
Join sysobjects o2
On fk.fkeyid = o2.id
Join sys.schemas s2
On o2.uid = s2.schema_id
Join #tables t
On o2.name = t.TableName Collate Database_Default
And s2.name = t.SchemaName Collate Database_Default
Where o.name = #table
And s1.name = #schema)
Begin
Update t
Set tID = (Select Max(tID) From #tables) + 1
From #tables t
Where tableName = #table
And schemaName = #schema
Set #iter = #iter + 1
End
Else
Begin
Set #Sql = 'Delete t
From [' + #schema + '].[' + #table + '] t
Where CorporationId = ''' + #corpID + ''''
Exec sp_executeSQL #SQL;
Delete t
From #tables t
Where tableName = #table
And schemaName = #schema
Set #iter = #iter + 1
End
End
You could run a query like this:
SELECT 'DELETE FROM [' + s.name + '].[' + t.name + '] WHERE CorporationId = ''52D3AEFE-8EBD-4669-8096-4596FE83BB36'''
FROM sys.columns c
inner join sys.tables t
ON t.object_id= c.object_id
inner join sys.schemas s
ON s.schema_id = t.schema_id
where c.name = 'CorporationId'
and then either copy and paste the results into a new query window and execute the new query or iterate over the results with a cursor and execute each result with the exec statement.
Here is a Sql Fiddle that proves the below query
You can get the tables from this query:
SELECT Name, IsChecked = 0
INTO #Tables
FROM sys.Tables
WHERE EXISTS
(
SELECT * FROM sys.columns
WHERE object_id = OBJECT_ID(sys.Tables.Name) AND sys.columns.Name = 'blah'
)
Then, you can create a dynamic query and execute it for the tables that you found
WHILE(SELECT COUNT(*) FROM #Tables WHERE IsChecked = 0) > 0
BEGIN
SELECT TOP 1 #TableName = Name FROM #Tables WHERE IsChecked = 0
SET #DeleteQuery = 'DELETE FROM ' + #TableName + ' WHERE CorporationID = ''' + #CorporationId + ''''
EXECUTE sp_executeSQL #DeleteQuery;
UPDATE #Tables SET IsChecked = 1 WHERE Name = #TableName
END

How to retrieve all indexes in a database along with their data types in SQL Server 2005?

I have a maintenance task that's failing because there are a few indexes on the database that have a type which does not allow online rebuilding of the index. Offline is not an option in my industry, so I have to create my own T-SQL task that does the index rebuilding on specific indexes. The database is large with many tables and indexes, so is there a way to query the system for all indexes and their data types?
This will show you all the columns for all indices, including the columns of 'base tables' like heaps and clustered index and all INCLUDE columns as well:
select o.name as [object_name],
ix.name as [index_name],
coalesce(c.name,cc.name) as [column_name],
t.name as [type_name],
coalesce(c.max_length, cc.max_length) as max_length
from sys.indexes ix
join sys.objects o
on ix.object_id = o.object_id
left join sys.index_columns ic
on ix.object_id = ic.object_id
and ix.index_id = ix.index_id
and ix.index_id > 1
left join sys.columns c
on ic.object_id = c.object_id
and ic.column_id = c.column_id
left join sys.columns cc
on ix.object_id = cc.object_id
and ix.index_id in (1,0)
join sys.types t
on t.system_type_id = coalesce(c.system_type_id,cc.system_type_id)
where o.type = 'U'
order by object_name, index_name, column_name;
You can then identify the ones unsafe for online index rebuild (the BLOB/XML/CLR types). Note that in SQL server 2012 the restriction on online index build with LOB columns was lifted, see Online Index Operations for indexes containing LOB columns.
we've made recently such procedure. it has "HasBlobs" flag for this purpose
ALTER PROCEDURE sp_rebuild_local_idexes
#RebuildClustered bit = 0
AS
BEGIN
DECLARE #objectid int
DECLARE #indexid int
DECLARE #schemaname nvarchar(130)
DECLARE #objectname nvarchar(130)
DECLARE #indexname nvarchar(130)
DECLARE #partitions bigint
DECLARE #frag float
DECLARE #command nvarchar(4000)
DECLARE #HasBlobs bit
DECLARE #index_type_desc nvarchar(255)
-- Conditionally select tables and indexes from the sys.dm_db_index_physical_stats function
-- and convert object and index IDs to names.
SELECT
--object_name(object_id),
object_id AS objectid,
index_id AS indexid,
avg_fragmentation_in_percent AS frag,
CASE WHEN (
SELECT st.object_id
from sys.tables st
inner join sys.columns sc
on st.object_id=sc.object_id
inner join sys.types styp
on sc.system_type_id=styp.system_type_id and sc.max_length=styp.max_length
inner join sys.schemas ss
on st.schema_id=ss.schema_id
where styp.schema_id=4
and styp.name<>'sysname'
and styp.name IN ('xml','nvarchar','varchar','image','text','ntext')
AND st.object_id = a.object_id
group by st.object_id
) IS NULL THEN 0 ELSE 1 END AS HasBlobs,
a.index_type_desc
INTO #work_to_do
FROM sys.dm_db_index_physical_stats (DB_ID(), NULL, NULL , NULL, 'LIMITED') AS a
WHERE avg_fragmentation_in_percent >= 5.0 AND index_id > 0
AND a.index_type_desc IN ('CLUSTERED INDEX','NONCLUSTERED INDEX')
ORDER BY a.index_type_desc
-- Declare the cursor for the list of partitions to be processed.
DECLARE partitions CURSOR FOR SELECT objectid,
indexid,
frag,
HasBlobs,
index_type_desc from #work_to_do
select * from #work_to_do
-- Open the cursor.
OPEN partitions
-- Loop through the partitions.
WHILE (1=1)
BEGIN
FETCH NEXT FROM partitions
INTO #objectid, #indexid, #frag,#HasBlobs,#index_type_desc
IF ##FETCH_STATUS < 0 BREAK
IF #RebuildClustered = 1 AND #index_type_desc != 'CLUSTERED INDEX'
CONTINUE;
SELECT #objectname = QUOTENAME(o.name), #schemaname = QUOTENAME(s.name)
FROM sys.objects AS o
JOIN sys.schemas as s ON s.schema_id = o.schema_id
WHERE o.object_id = #objectid
SELECT #indexname = QUOTENAME(name)
FROM sys.indexes
WHERE object_id = #objectid AND index_id = #indexid and type!=3
-- 30 is an arbitrary decision point at which to switch between reorganizing and rebuilding.
IF #frag < 30.0
SET #command = N'ALTER INDEX ' + #indexname + N' ON ' + #schemaname + N'.' + #objectname + N' REORGANIZE'
IF #frag >= 30.0
BEGIN
print #indexname+ #schemaname+#objectname
SET #command = N'ALTER INDEX ' + #indexname +
N' ON ' +
#schemaname +
N'.' + #objectname +
N' REBUILD' +
CASE WHEN #HasBlobs = 0 THEN ' WITH(ONLINE=ON)' ELSE '' END
print #command
END
EXEC (#command)
PRINT N'Executed: ' + #command
END
-- Close and deallocate the cursor.
CLOSE partitions
DEALLOCATE partitions
END

Resources