The title pretty much sums up what I am looking for. So I am looking to get some meta information for sql indexes for eg. TableName, SchemaName, DatabaseName.
SELECT
TableName = t.name,
IndexName = ind.name,
IndexId = ind.index_id,
ColumnId = ic.index_column_id,
ColumnName = col.name,
SchemaName = s.name
FROM
sys.indexes ind
INNER JOIN
sys.index_columns ic ON ind.object_id = ic.object_id and ind.index_id = ic.index_id
INNER JOIN
sys.columns col ON ic.object_id = col.object_id and ic.column_id = col.column_id
INNER JOIN
sys.tables t ON ind.object_id = t.object_id
INNER JOIN
sys.schemas s ON t.schema_id = s.schema_id
WHERE
ind.name = 'testindex'
ORDER BY
t.name, ind.name, ind.index_id, ic.index_column_id;
So far I have managed to get TableName and SchemaName for an index, however I don't know how to get the database name.
Using Aaron Bertrand's script for making a more reliable and flexible sp_MSforeachdb
, you can use your query with a modification.
You will need to use this, or a cursor, or some other method to iterate over all databases on your server. This is one of the bests I have seen, since Microsoft's version can skip databases as Aaron points out.
sp_foreachdb Method
CREATE PROCEDURE dbo.sp_foreachdb
@command NVARCHAR(MAX),
@replace_character NCHAR(1) = N'?',
@print_dbname BIT = 0,
@print_command_only BIT = 0,
@suppress_quotename BIT = 0,
@system_only BIT = NULL,
@user_only BIT = NULL,
@name_pattern NVARCHAR(300) = N'%',
@database_list NVARCHAR(MAX) = NULL,
@recovery_model_desc NVARCHAR(120) = NULL,
@compatibility_level TINYINT = NULL,
@state_desc NVARCHAR(120) = N'ONLINE',
@is_read_only BIT = 0,
@is_auto_close_on BIT = NULL,
@is_auto_shrink_on BIT = NULL,
@is_broker_enabled BIT = NULL
AS
BEGIN
SET NOCOUNT ON;
DECLARE
@sql NVARCHAR(MAX),
@dblist NVARCHAR(MAX),
@db NVARCHAR(300),
@i INT;
IF @database_list > N''
BEGIN
;WITH n(n) AS
(
SELECT ROW_NUMBER() OVER (ORDER BY s1.name) - 1
FROM sys.objects AS s1
CROSS JOIN sys.objects AS s2
)
SELECT @dblist = REPLACE(REPLACE(REPLACE(x,'</x><x>',','),
'</x>',''),'<x>','')
FROM
(
SELECT DISTINCT x = 'N''' + LTRIM(RTRIM(SUBSTRING(
@database_list, n,
CHARINDEX(',', @database_list + ',', n) - n))) + ''''
FROM n WHERE n <= LEN(@database_list)
AND SUBSTRING(',' + @database_list, n, 1) = ','
FOR XML PATH('')
) AS y(x);
END
CREATE TABLE #x(db NVARCHAR(300));
SET @sql = N'SELECT name FROM sys.databases WHERE 1=1'
+ CASE WHEN @system_only = 1 THEN
' AND database_id IN (1,2,3,4)'
ELSE '' END
+ CASE WHEN @user_only = 1 THEN
' AND database_id NOT IN (1,2,3,4)'
ELSE '' END
+ CASE WHEN @name_pattern <> N'%' THEN
' AND name LIKE N''%' + REPLACE(@name_pattern, '''', '''''') + '%'''
ELSE '' END
+ CASE WHEN @dblist IS NOT NULL THEN
' AND name IN (' + @dblist + ')'
ELSE '' END
+ CASE WHEN @recovery_model_desc IS NOT NULL THEN
' AND recovery_model_desc = N''' + @recovery_model_desc + ''''
ELSE '' END
+ CASE WHEN @compatibility_level IS NOT NULL THEN
' AND compatibility_level = ' + RTRIM(@compatibility_level)
ELSE '' END
+ CASE WHEN @state_desc IS NOT NULL THEN
' AND state_desc = N''' + @state_desc + ''''
ELSE '' END
+ CASE WHEN @is_read_only IS NOT NULL THEN
' AND is_read_only = ' + RTRIM(@is_read_only)
ELSE '' END
+ CASE WHEN @is_auto_close_on IS NOT NULL THEN
' AND is_auto_close_on = ' + RTRIM(@is_auto_close_on)
ELSE '' END
+ CASE WHEN @is_auto_shrink_on IS NOT NULL THEN
' AND is_auto_shrink_on = ' + RTRIM(@is_auto_shrink_on)
ELSE '' END
+ CASE WHEN @is_broker_enabled IS NOT NULL THEN
' AND is_broker_enabled = ' + RTRIM(@is_broker_enabled)
ELSE '' END;
INSERT #x EXEC sp_executesql @sql;
DECLARE c CURSOR
LOCAL FORWARD_ONLY STATIC READ_ONLY
FOR SELECT CASE WHEN @suppress_quotename = 1 THEN
db
ELSE
QUOTENAME(db)
END
FROM #x ORDER BY db;
OPEN c;
FETCH NEXT FROM c INTO @db;
WHILE @@FETCH_STATUS = 0
BEGIN
SET @sql = REPLACE(@command, @replace_character, @db);
IF @print_command_only = 1
BEGIN
PRINT '/* For ' + @db + ': */'
+ CHAR(13) + CHAR(10) + CHAR(13) + CHAR(10)
+ @sql
+ CHAR(13) + CHAR(10) + CHAR(13) + CHAR(10);
END
ELSE
BEGIN
IF @print_dbname = 1
BEGIN
PRINT '/* ' + @db + ' */';
END
EXEC sp_executesql @sql;
END
FETCH NEXT FROM c INTO @db;
END
CLOSE c;
DEALLOCATE c;
END
Execution of Proc
EXEC sp_foreachdb
@command = 'SELECT
DBNAME = ''?'',
TableName = t.name,
IndexName = ind.name,
IndexId = ind.index_id,
ColumnId = ic.index_column_id,
ColumnName = col.name,
SchemaName = s.name
FROM
?.sys.indexes ind
INNER JOIN
?.sys.index_columns ic ON ind.object_id = ic.object_id and ind.index_id = ic.index_id
INNER JOIN
?.sys.columns col ON ic.object_id = col.object_id and ic.column_id = col.column_id
INNER JOIN
?.sys.tables t ON ind.object_id = t.object_id
INNER JOIN
?.sys.schemas s ON t.schema_id = s.schema_id
ORDER BY
t.name, ind.name, ind.index_id, ic.index_column_id'
,@print_command_only = 0
No Proc & No Cursor Method
Thanks to Sean Lange for reminding me how, you can use a hack of variable concatenation to not use a cursor, or a procedure, and accomplish the same task.
declare @sql varchar(max) = ''
select @sql = @sql
+ 'use '
+ quotename(name)
+ char(13)
+ 'select DBNAME = '''
+ name
+ ''',
TableName = t.name,
IndexName = ind.name,
IndexId = ind.index_id,
ColumnId = ic.index_column_id,
ColumnName = col.name,
SchemaName = s.name
FROM
sys.indexes ind
INNER JOIN
sys.index_columns ic ON ind.object_id = ic.object_id and ind.index_id = ic.index_id
INNER JOIN
sys.columns col ON ic.object_id = col.object_id and ic.column_id = col.column_id
INNER JOIN
sys.tables t ON ind.object_id = t.object_id
INNER JOIN
sys.schemas s ON t.schema_id = s.schema_id; '
+ char(13)
from sys.databases
where state = 0
exec(@sql)
I use something like this.
select t.name, i.name, t.object_id,
STUFF((
select N' , ' + name
from sys.columns c
join sys.index_columns ic on ic.object_id = c.object_id and ic.column_id = c.column_id
where ic.object_id = i.object_id and c.object_id = i.object_id
and ic.index_id = i.index_id
and ic.is_included_column=0
order by ic.is_included_column, ic.key_ordinal
FOR XML PATH(''),TYPE).value('text()[1]','nvarchar(max)'),1,2,N''
) IndexKeyColumns
,
STUFF((
select N' , ' + name
from sys.columns c
join sys.index_columns ic on ic.object_id = c.object_id and ic.column_id = c.column_id
where ic.object_id = i.object_id and c.object_id = i.object_id
and ic.index_id = i.index_id
and ic.is_included_column=1
order by ic.is_included_column, ic.key_ordinal
FOR XML PATH(''),TYPE).value('text()[1]','nvarchar(max)'),1,2,N''
) IncludedColumns
from sys.indexes i
join sys.tables t on t.object_id = i.object_id
where i.type in (1,2)
and i.is_primary_key = 0
order by t.name, i.name
You can execute against your dbs with dynamic sql
declare myDatabases cursor for
select name from sys.databases
where name in ('db1','db2') -- leave this out for all of them
order by name
declare @tempDBName varchar(200)
open myDatabases
fetch next from mydatabases into @tempDBName
while @@FETCH_STATUS = 0
begin
declare @sql nvarchar(max)
set @sql = N'
declare @innersql nvarchar(max) = ''use ''+@tempDBName
set @innersql = @innersql +''
select db_name()
''
exec (@innersql)
'
exec sp_executesql @sql,N'@tempDBName varchar(200)',@tempDBName
fetch next from myDatabases into @tempDBName
end
close myDatabases
deallocate myDatabases
Putting it together with your query, rather than mine (many quotes to sort out) it would be something like this... pull out the where clause line entirely should get you your selection
declare myDatabases cursor for
select name from sys.databases
where name in ('db1','db2')
order by name
declare @tempDBName varchar(200)
open myDatabases
fetch next from mydatabases into @tempDBName
while @@FETCH_STATUS = 0
begin
declare @sql nvarchar(max)
set @sql = N'
declare @innersql nvarchar(max) = ''use ''+@tempDBName
set @innersql = @innersql +
'''
+
--select db_name()
'
SELECT
TableName = t.name,
IndexName = ind.name,
IndexId = ind.index_id,
ColumnId = ic.index_column_id,
ColumnName = col.name,
SchemaName = s.name
FROM
sys.indexes ind
INNER JOIN
sys.index_columns ic ON ind.object_id = ic.object_id and ind.index_id = ic.index_id
INNER JOIN
sys.columns col ON ic.object_id = col.object_id and ic.column_id = col.column_id
INNER JOIN
sys.tables t ON ind.object_id = t.object_id
INNER JOIN
sys.schemas s ON t.schema_id = s.schema_id
WHERE
ind.name = ''''testindex''''
ORDER BY
t.name, ind.name, ind.index_id, ic.index_column_id;
'
+
'''
exec (@innersql)
'
exec sp_executesql @sql,N'@tempDBName varchar(200)',@tempDBName
fetch next from myDatabases into @tempDBName
end
close myDatabases
deallocate myDatabases
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.