RealWorldDevelopers
9/19/2016 - 11:22 PM

Script all Keys and Indexes in a SQL Database

Script all Keys and Indexes in a SQL Database

-- Script out indexes completely, including both PK's and regular indexes, each clustered or nonclustered.  
 -- DOES NOT HANDLE COMPRESSION; that's ok, since 2008 R2 RTM benchmarking shows it's faster and results in smaller indexes to insert uncompressed and then compress later  
 -- HARDCODES [dbo] schema (i.e. it doesn't say [JohnDoe].[table], changing that to [dbo].[table]  
 -- originally from   http://www.sqlservercentral.com/Forums/Topic961088   -2753-2.aspx  

 DECLARE  
 @idxTableName SYSNAME,  
 @idxTableID   INT   ,  
 @idxname SYSNAME,  
 @idxid   INT   ,  
 @colCount   INT   ,  
 @IxColumn SYSNAME,  
 @IxFirstColumn   BIT   ,  
 @ColumnIDInTable   INT   ,  
 @ColumnIDInIndex   INT   ,  
 @IsIncludedColumn   INT   ,  
 @sIncludeCols VARCHAR(   MAX   ),  
 @sIndexCols VARCHAR(   MAX   ),  
 @sSQL VARCHAR(   MAX   ),  
 @sParamSQL VARCHAR(   MAX   ),  
 @sFilterSQL VARCHAR(   MAX   ),  
 @location SYSNAME,  
 @IndexCount   INT   ,  
 @CurrentIndex   INT   ,  
 @CurrentCol   INT   ,  
 @   NAME   VARCHAR(128),  
 @IsPrimaryKey TINYINT,  
 @Fillfactor   INT   ,  
 @FilterDefinition VARCHAR(   MAX   ),  
 @IsClustered   BIT    -- used solely for putting information into the result table  


 IF   EXISTS   (SELECT   *   FROM tempdb.dbo.sysobjects WHERE id   =   object_id(N   '[tempdb].[dbo].[#IndexSQL]'   ))  
 DROP    TABLE   [dbo].[   #   IndexSQL]  

 CREATE    TABLE    #   IndexSQL  
 ( TableName VARCHAR(128)   NOT    NULL  
 ,IndexName VARCHAR(128)   NOT    NULL  
 ,IsClustered   BIT    NOT    NULL  
 ,IsPrimaryKey   BIT    NOT    NULL  
 ,IndexCreateSQL VARCHAR(   MAX   )   NOT    NULL  
 )  

 IF   EXISTS   (SELECT   *   FROM tempdb.dbo.sysobjects WHERE id   =   object_id(N   '[tempdb].[dbo].[#IndexListing]'   ))  
 DROP    TABLE   [dbo].[   #   IndexListing]  

 CREATE    TABLE    #   IndexListing  
 (  
 [IndexListingID]   INT    IDENTITY   (1,1)   PRIMARY    KEY   CLUSTERED,  
 [TableName] SYSNAME   COLLATE   SQL_Latin1_General_CP1_CI_AS   NULL   ,  
 [ObjectID]   INT    NOT    NULL   ,  
 [IndexName] SYSNAME   COLLATE   SQL_Latin1_General_CP1_CI_AS   NULL   ,  
 [IndexID]   INT    NOT    NULL   ,  
 [IsPrimaryKey] TINYINT   NOT    NULL   ,  
 [FillFactor]   INT   ,  
 [FilterDefinition] NVARCHAR(   MAX   )   NULL  
 )  

 IF   EXISTS   (SELECT   *   FROM tempdb.dbo.sysobjects WHERE id   =   object_id(N   '[tempdb].[dbo].[#ColumnListing]'   ))  
 DROP    TABLE   [dbo].[   #   ColumnListing]  

 CREATE    TABLE    #   ColumnListing  
 (  
 [ColumnListingID]   INT    IDENTITY   (1,1)   PRIMARY    KEY   CLUSTERED,  
 [ColumnIDInTable]   INT    NOT    NULL   ,  
 [   NAME   ] SYSNAME   COLLATE   SQL_Latin1_General_CP1_CI_AS   NULL   ,  
 [ColumnIDInIndex]   INT    NOT    NULL   ,  
 [IsIncludedColumn]   BIT    NULL  
 )  

 INSERT INTO    #   IndexListing( [TableName], [ObjectID], [IndexName], [IndexID], [IsPrimaryKey], [FILLFACTOR], [FilterDefinition] )  
 SELECT   OBJECT_NAME(si.object_id), si.object_id, si.   NAME   , si.index_id, si.Is_Primary_Key, si.Fill_Factor, si.filter_definition  
 FROM   sys.indexes si  
 LEFT    OUTER    JOIN   information_schema.table_constraints tc   ON   si.   NAME    =   tc.   CONSTRAINT_NAME    AND   OBJECT_NAME(si.object_id)   =   tc.   TABLE_NAME  
 WHERE   OBJECTPROPERTY(si.object_id,   'IsUserTable'   )   =   1  
 ORDER BY   OBJECT_NAME(si.object_id), si.index_id  

 SELECT   @IndexCount   =   @@ROWCOUNT, @CurrentIndex   =   1  

 WHILE @CurrentIndex   <=   @IndexCount  
 BEGIN  

 SELECT   @idxTableName   =   [TableName],  
 @idxTableID   =   [ObjectID],  
 @idxname   =   [IndexName],  
 @idxid   =   [IndexID],  
 @IsPrimaryKey   =   [IsPrimaryKey],  
 @FillFactor   =   [FILLFACTOR],  
 @FilterDefinition   =   [FilterDefinition]  
 FROM    #   IndexListing  
 WHERE   [IndexListingID]   =   @CurrentIndex  

 -- So - it is either an index or a constraint  
 -- Check if the index is unique  
 IF (@IsPrimaryKey   =   1)  
 BEGIN  
  SET   @sSQL   =    'ALTER TABLE [dbo].['    +   @idxTableName   +    '] ADD CONSTRAINT ['    +   @idxname   +    '] PRIMARY KEY '  
  -- Check if the index is clustered  
 IF (INDEXPROPERTY(@idxTableID, @idxname,   'IsClustered'   )   =   0)  
  BEGIN  
  SET   @sSQL   =   @sSQL   +    'NON'  
  SET   @IsClustered   =   0  
  END  
  ELSE  
  BEGIN  
  SET   @IsClustered   =   1  
  END  
  SET   @sSQL   =   @sSQL   +    'CLUSTERED'    +    CHAR   (13)   +    '('    +    CHAR   (13)  
 END  
 ELSE  
 BEGIN  
  SET   @sSQL   =    'CREATE '  
  -- Check if the index is unique  
 IF (INDEXPROPERTY(@idxTableID, @idxname,   'IsUnique'   )   =   1)  
  BEGIN  
  SET   @sSQL   =   @sSQL   +    'UNIQUE '  
  END  
  -- Check if the index is clustered  
 IF (INDEXPROPERTY(@idxTableID, @idxname,   'IsClustered'   )   =   1)  
  BEGIN  
  SET   @sSQL   =   @sSQL   +    'CLUSTERED '  
  SET   @IsClustered   =   1  
  END  
  ELSE  
  BEGIN  
  SET   @IsClustered   =   0  
  END  

  SELECT  
 @sSQL   =   @sSQL   +    'INDEX ['    +   @idxname   +    '] ON [dbo].['    +   @idxTableName   +    ']'    +    CHAR   (13)   +    '('    +    CHAR   (13),  
 @colCount   =   0  
 END  

 -- Get the number of cols in the index  
 SELECT   @colCount   =    COUNT   (   *   )  
 FROM   sys.index_columns ic  
 INNER    JOIN   sys.columns sc   ON   ic.object_id   =   sc.object_id   AND   ic.column_id   =   sc.column_id  
 WHERE   ic.object_id   =   @idxtableid   AND   index_id   =   @idxid   AND   ic.is_included_column   =   0  

 -- Get the file group info  
 SELECT   @location   =   f.[   NAME   ]  
 FROM   sys.indexes i  
 INNER    JOIN   sys.filegroups f   ON   i.data_space_id   =   f.data_space_id  
 INNER    JOIN   sys.all_objects o   ON   i.[object_id]   =   o.[object_id]  
 WHERE   o.object_id   =   @idxTableID   AND   i.index_id   =   @idxid  

 -- Get all columns of the index  
 INSERT INTO    #   ColumnListing( [ColumnIDInTable], [   NAME   ], [ColumnIDInIndex],[IsIncludedColumn] )  
 SELECT   sc.column_id, sc.   NAME   , ic.index_column_id, ic.is_included_column  
 FROM   sys.index_columns ic  
 INNER    JOIN   sys.columns sc   ON   ic.object_id   =   sc.object_id   AND   ic.column_id   =   sc.column_id  
 WHERE   ic.object_id   =   @idxTableID   AND   index_id   =   @idxid  
 ORDER BY   ic.index_column_id  

 IF @@ROWCOUNT   >   0  
 BEGIN  

 SELECT   @CurrentCol   =   1  

 SELECT   @IxFirstColumn   =   1, @sIncludeCols   =    ''   , @sIndexCols   =    ''  

 WHILE @CurrentCol   <=   @ColCount  
 BEGIN  
 SELECT   @ColumnIDInTable   =   ColumnIDInTable,  
 @   NAME    =    NAME   ,  
 @ColumnIDInIndex   =   ColumnIDInIndex,  
 @IsIncludedColumn   =   IsIncludedColumn  
 FROM    #   ColumnListing  
 WHERE   [ColumnListingID]   =   @CurrentCol  

 IF @IsIncludedColumn   =   0  
 BEGIN  

 SET   @sIndexCols   =    CHAR   (9)   +   @sIndexCols   +    '['    +   @   NAME    +    '] '  

 -- Check the sort order of the index cols ????????  
 IF (INDEXKEY_PROPERTY (@idxTableID,@idxid,@ColumnIDInIndex,   'IsDescending'   ))   =   0  
 BEGIN  
 SET   @sIndexCols   =   @sIndexCols   +    ' ASC '  
 END  
 ELSE  
 BEGIN  
 SET   @sIndexCols   =   @sIndexCols   +    ' DESC '  
 END  

 IF @CurrentCol   <   @colCount  
 BEGIN  
 SET   @sIndexCols   =   @sIndexCols   +    ', '  
 END  

 END  
 ELSE  
 BEGIN  
 -- Check for any include columns  
 IF LEN(@sIncludeCols)   >   0  
 BEGIN  
 SET   @sIncludeCols   =   @sIncludeCols   +    ','  
 END  

 SET   @sIncludeCols   =   @sIncludeCols   +    '['    +   @IxColumn   +    ']'  

 END  

 SET   @CurrentCol   =   @CurrentCol   +   1  
 END  

 TRUNCATE   TABLE    #   ColumnListing  

 --append to the result  
 IF LEN(@sIncludeCols)   >   0  
  SET   @sIndexCols   =   @sSQL   +   @sIndexCols   +    CHAR   (13)   +    ') '    +    ' INCLUDE ( '    +   @sIncludeCols   +    ' ) '  
 ELSE  
  SET   @sIndexCols   =   @sSQL   +   @sIndexCols   +    CHAR   (13)   +    ') '  

 -- Add filtering  
 IF @FilterDefinition   IS    NOT    NULL  
  SET   @sFilterSQL   =    ' WHERE '    +   @FilterDefinition   +    ' '    +    CHAR   (13)  
 ELSE  
  SET   @sFilterSQL   =    ''  

 ---- Build the options  
 --SET @sParamSQL = 'WITH ( PAD_INDEX = '  
 --IF INDEXPROPERTY(@idxTableID, @idxname, 'IsPadIndex') = 1  
 -- SET @sParamSQL = @sParamSQL + 'ON,'  
 --ELSE  
 -- SET @sParamSQL = @sParamSQL + 'OFF,'  

 --SET @sParamSQL = @sParamSQL + ' ALLOW_PAGE_LOCKS = '  
 --IF INDEXPROPERTY(@idxTableID, @idxname, 'IsPageLockDisallowed') = 0  
 -- SET @sParamSQL = @sParamSQL + 'ON,'  
 --ELSE  
 -- SET @sParamSQL = @sParamSQL + 'OFF,'  

 --SET @sParamSQL = @sParamSQL + ' ALLOW_ROW_LOCKS = '  
 --IF INDEXPROPERTY(@idxTableID, @idxname, 'IsRowLockDisallowed') = 0  
 --SET @sParamSQL = @sParamSQL + 'ON,'  
 --ELSE  
 --SET @sParamSQL = @sParamSQL + 'OFF,'  


 --SET @sParamSQL = @sParamSQL + ' STATISTICS_NORECOMPUTE = '  
 ---- THIS DOES NOT WORK PROPERLY; IsStatistics only says what generated the last set, not what it was set to do.  
 --IF (INDEXPROPERTY(@idxTableID, @idxname, 'IsStatistics') = 1)  
 --SET @sParamSQL = @sParamSQL + 'ON'  
 --ELSE  
 --SET @sParamSQL = @sParamSQL + 'OFF'  

 -- Fillfactor 0 is actually not a valid percentage on SQL 2008 R2  
 --IF ISNULL( @FillFactor, 90 ) <> 0  
 -- SET @sParamSQL = @sParamSQL + ' ,FILLFACTOR = ' + CAST( ISNULL( @FillFactor, 90 ) AS VARCHAR(3) )  


 --IF (@IsPrimaryKey = 1) -- DROP_EXISTING isn't valid for PK's  
 --BEGIN  
 -- SET @sParamSQL = @sParamSQL + ' ) '  
 --END  
 --ELSE  
 --BEGIN  
 -- SET @sParamSQL = @sParamSQL + ' ,DROP_EXISTING = ON ) '  
 --END  

 SET   @sSQL   =   @sIndexCols   +    CHAR   (13)   +   @sFilterSQL   +    CHAR   (13)   --+ @sParamSQL  

 -- 2008 R2 allows ON [filegroup] for primary keys as well, negating the old "IF THE INDEX IS NOT A PRIMARY KEY - ADD THIS - ELSE DO NOT" IsPrimaryKey IF statement  
 SET   @sSQL   =   @sSQL   +    ' ON ['    +   @location   +    ']'  

 --PRINT @sIndexCols + CHAR(13)  
 INSERT INTO    #   IndexSQL (TableName, IndexName, IsClustered, IsPrimaryKey, IndexCreateSQL)   VALUES   (@idxTableName, @idxName, @IsClustered, @IsPrimaryKey, @sSQL)  

 END  

 SET   @CurrentIndex   =   @CurrentIndex   +   1  
 END  

 SELECT    *    FROM    #   IndexSQL   ORDER BY   1,