How to get the Index Name from IndexId in SQL Server 2005 - sql-server

I'm running the following query to list size and fragmentation of the indexes:
SELECT object_name(object_id, database_id) as objectname), index_id, *
FROM sys.dm_db_index_usage_stats
Is there an SQL function I can use to convert the index_id to the index name?

I found a function on this page that should help you out:
CREATE FUNCTION dbo.index_name (#object_id int, #index_id int)
RETURNS sysname
AS
BEGIN
RETURN(SELECT name FROM sys.indexes WHERE object_id = #object_id and index_id = #index_id)
END;

Or better yet:
SELECT OBJECT_NAME(d.object_id, d.database_id) AS objectname ,
d.index_id ,
i.name ,
*
FROM sys.dm_db_index_usage_stats AS d
LEFT OUTER JOIN sys.indexes AS i ON i.object_id = d.object_id
AND i.index_id = d.index_id

I have come with this solution, works great:
create table dbo.IndexNames
(database_id int not null, object_id int not null, index_id int not null, index_name sysname not null)
go
create procedure dbo.GatherIndexNames
as
begin
declare #cur cursor
,#name varchar(128)
,#sql varchar(max)
truncate table dbo.IndexNames
set #cur = cursor for select name from sys.databases
where database_id >= 5
open #cur
fetch next from #cur into #name
while ##fetch_status = 0
begin
set #sql = '
insert into dbo.IndexNames
(database_id, object_id, index_id, index_name)
select db_id(''' + #name + '''),t.object_id, i.index_id, i.name
from [' + #name + '].[sys].[tables] t
inner join [' + #name + '].[sys].[indexes] i
on t.OBJECT_ID = i.object_id
where i.index_id <> 0'
exec (#sql)
fetch next from #cur into #name
end

Related

Iterate through all DBs - Get constraints in all tables

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;

SQL Server : select columns of a table then select top 1 value

Is there a way to select columns of a table then assign the top 1 value of that column.
For example
TABLENAME | COLUMNNAME | VALUE
----------+------------+---------------
TABLE 1 | COLUMN 1 | COLUMN 1 VALUE
TABLE 1 | COLUMN 2 | COLUMN 2 VALUE
UPDATE
DECLARE #tableCOLS TABLE (tablename varchar(255) , colname varchar(255));
BEGIN
SET #MyCursor = CURSOR FOR
SELECT DISTINCT tablename FROM #tableid
OPEN #MyCursor
FETCH NEXT FROM #MyCursor
INTO #MyField2
WHILE ##FETCH_STATUS = 0
BEGIN
INSERT INTO #tableCOLS
SELECT #MyField2 , COLUMN_NAME
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = #MyField2
FETCH NEXT FROM #MyCursor
INTO #MyField2
END;
CLOSE #MyCursor ;
DEALLOCATE #MyCursor;
END;
SELECT * from #tableCOLS
END;
I fetch the table columns to my dynamic table then i want to insert the value of a certain data in the columns that i fetch in my table
I just tested this and it works a treat
DECLARE #Result TABLE (TableName VARCHAR(50), Col VARCHAR(50), MaxValue VARCHAR(50), MaxSQL NVARCHAR(4000));
DECLARE #TableName VARCHAR(50), #Col VARCHAR(50), #MaxSQL NVARCHAR(4000), #MaxValue VARCHAR(50)
-- Load all tables and columns of interest
INSERT INTO #Result
(TableName, Col, MaxSQL)
select
object_name(object_id),
name,
'SELECT #C = MAX(' + name + ') FROM ' + object_name(object_id)
from sys.columns where object_name(object_id) = 'Table1'
-- For each row, run the dynamic SQL and update back into table
DECLARE c CURSOR FOR
SELECT TableName, Col, MaxSQL FROM #Result
OPEN c
FETCH NEXT FROM C INTO #TableName, #Col, #MaxSQL
WHILE ##FETCH_STATUS = 0
BEGIN
EXEC sp_ExecuteSQL #MaxSQL, N'#C VARCHAR(50) OUTPUT', #C = #MaxValue OUTPUT
UPDATE #Result SET MaxValue = #MaxValue WHERE TableName = #TableName AND Col = #Col;
FETCH NEXT FROM C INTO #TableName, #Col, #MaxSQL
END
CLOSE c;
DEALLOCATE c;
-- Show the results
SELECT * FROM #Result;
There's no need to use loops or cursors to do this. Have a look at the following...
SET NOCOUNT ON;
DECLARE #Object_id INT = OBJECT_ID('DataBaseName.Schema.TableName');
IF OBJECT_ID('tempdb..#TableCols', 'U') IS NOT NULL
DROP TABLE #TableCols;
CREATE TABLE #TableCols (
SchemaName sysname,
TableName sysname,
ColumnName sysname,
ColumnID INT NOT NULL,
Value NVARCHAR(MAX) NULL
);
INSERT #TableCols (SchemaName, TableName, ColumnName, ColumnID)
SELECT
s.name,
o.name,
c.name,
c.column_id
FROM
sys.objects o
JOIN sys.schemas s
ON o.schema_id = s.schema_id
JOIN sys.columns c
ON o.object_id = c.object_id
WHERE
o.type = 'U'
AND o.object_id = #Object_id
ORDER BY
c.column_id;
DECLARE
#CrossCols VARCHAR(MAX) = N'',
#TopVal NVARCHAR(10) = N'',
#Table sysname = N'',
#sql NVARCHAR(MAX) = N'',
#DeBug BIT = 0; -- 1 = PRINT ; 0 = EXECUTE
SELECT
#CrossCols = CONCAT(#CrossCols, N',
(', tc.ColumnID, N', CAST(t.[', tc.ColumnName, N'] AS NVARCHAR(MAX)))'),
#TopVal = tc.ColumnID,
#Table = CONCAT(tc.SchemaName, '.', tc.TableName)
FROM
#TableCols tc
ORDER BY
tc.ColumnID;
SET #sql = CONCAT(N'
UPDATE tc SET
tc.Value = t.ColumnValue
FROM
#TableCols tc
JOIN (
SELECT TOP (', #TopVal, N')
x.*
FROM
', #Table, N' t
CROSS APPLY ( VALUES', STUFF(#CrossCols, 1, 1, ''), N'
) x (ColumnID, ColumnValue)
) t
ON tc.ColumnID = t.ColumnID;')
IF #DeBug = 1
BEGIN
EXEC dbo.LongPrint #sql;
END;
ELSE
BEGIN
EXEC(#sql);
SELECT * FROM #TableCols tc;
END;
Give this a shot...
DECLARE #Table VARCHAR(MAX) = 'Customer'
SELECT t.name AS [Table]
, c.name AS [Column]
, cmd.mycmd
, TYPE_NAME(c.user_type_id) AS [Type]
, c.max_length AS [Size]
, CASE WHEN c.is_nullable = 1 THEN ''
ELSE 'No Nulls' END AS Nullable
, ROW_NUMBER() OVER ( PARTITION BY t.name ORDER BY c.name ASC ) AS rnk
, CASE WHEN EXISTS ( SELECT 1
FROM sys.columns c2
WHERE c2.object_id = t.object_id
AND c2.name IN ( SELECT *
FROM dbo.fnSplit('Fieldnames,ToSkip', ',') ) ) THEN 'Y'
ELSE 'N' END AS [CreModDeLs]
into #MyTempTable
FROM sys.columns AS c
JOIN sys.tables AS t ON c.object_id = t.object_id
cross apply (Select 'Select top 1 #Val = cast(' + c.name + ' as varchar(max)) from ' + t.name + ' Order by 1 desc' as mycmd) cmd
WHERE t.name LIKE #Table
ORDER BY t.name
, c.name
alter table #MyTempTable add [Id] integer identity(1,1)
alter table #MyTempTable add [Top1Val] Varchar(max)
Declare #DynamicSQL as nvarchar(1000);
Declare #dynamicparamdec nvarchar(1000) = '#val Varchar(max) Output'
Declare #valueofid as int
Declare #returnval as varchar(max)
Declare #Id integer
DECLARE #MyCursor CURSOR FAST_FORWARD
FOR
SELECT id
, mycmd
FROM #MyTempTable
where type <> 'image'
OPEN #MyCursor
FETCH #MyCursor INTO #id, #DynamicSQL
WHILE ##fetch_status = 0
BEGIN
print #dynamicsql
execute sp_executesql #DynamicSQL
, #dynamicparamdec
, #returnval output
update #MyTempTable
set Top1Val = #returnval
where id = #id
FETCH #MyCursor INTO #id, #DynamicSQL
END
--Close the cursor, if it is empty then deallocate it:
IF ( SELECT CURSOR_STATUS('global', '#MyCursor') ) >= -1
BEGIN
IF ( SELECT CURSOR_STATUS('global', '#MyCursor') ) > -1
BEGIN
CLOSE #MyCursor
END
DEALLOCATE #MyCursor
END
select * from #MyTempTable

Count Rows Across Multiple SQL Server Databases

I'm trying to count the rows of all tables called tblDoc from every database in my SQL Server instance.
I tried this but apparently you can't access or declare variables in cursors:
DECLARE #dbname nvarchar(1000);
DECLARE #sqlCommand NVARCHAR(1000)
DECLARE #results TABLE(numberOfDocuments bigint);
DECLARE c1 CURSOR READ_ONLY
FOR
SELECT '[' + name + ']' FROM sys.databases WHERE name <> 'tempdb'
OPEN c1
FETCH NEXT FROM c1
INTO #dbname
WHILE ##FETCH_STATUS = 0
BEGIN
SET #sqlCommand = 'INSERT INTO results SELECT COUNT(ID) FROM ' + #dbname + '.dbo.tblDoc;';
print #sqlCommand;
EXECUTE sp_executesql #sqlCommand
FETCH NEXT FROM c1
INTO #dbname
END
CLOSE c1
DEALLOCATE c1
SELECT COUNT(numberOfDocuments) from #results;
Use Temp table instead
DECLARE #dbname nvarchar(1000);
DECLARE #sqlCommand NVARCHAR(1000)
CREATE TABLE #results (numberOfDocuments bigint);
DECLARE c1 CURSOR READ_ONLY
FOR
SELECT '[' + name + ']' FROM sys.databases WHERE name <> 'tempdb'
OPEN c1
FETCH NEXT FROM c1
INTO #dbname
WHILE ##FETCH_STATUS = 0
BEGIN
SET #sqlCommand = 'INSERT INTO #results SELECT COUNT(ID) FROM ' + #dbname + '.dbo.tblDoc;';
print #sqlCommand;
EXECUTE sp_executesql #sqlCommand
FETCH NEXT FROM c1
INTO #dbname
END
CLOSE c1
DEALLOCATE c1
SELECT COUNT(numberOfDocuments) from #results;
Raj
If you are looking for All table counts from All DB's in a given server then below solution is very simplified.
DECLARE #dbname nvarchar(1000);
DECLARE #sqlCommand NVARCHAR(1000)
drop table if exists ##temp
create table ##temp (dbname varchar(500),schemaname varchar(500),tablename varchar(500),counts int)
DECLARE c1 CURSOR READ_ONLY
FOR
SELECT name FROM master.sys.databases WHERE name NOT IN ('master', 'tempdb', 'model', 'msdb');
OPEN c1
FETCH NEXT FROM c1
INTO #dbname
WHILE ##FETCH_STATUS = 0
BEGIN
SET #sqlCommand = 'INSERT INTO ##temp'+'
SELECT
'''+#dbname+''' as databasename,
s.name AS schemaname,
t.name AS tablename,
p.rows AS rowcounts
FROM '+#dbname+'.sys.tables t
INNER JOIN '+#dbname+'.sys.indexes i ON t.OBJECT_ID = i.object_id
INNER JOIN '+#dbname+'.sys.partitions p ON i.object_id = p.OBJECT_ID AND i.index_id = p.index_id
INNER JOIN '+#dbname+'.sys.allocation_units a ON p.partition_id = a.container_id
LEFT OUTER JOIN '+#dbname+'.sys.schemas s ON t.schema_id = s.schema_id
WHERE t.NAME NOT LIKE ''dt%''
AND t.is_ms_shipped = 0
AND i.OBJECT_ID > 255
GROUP BY
t.name, s.name, p.Rows
'
;
print #sqlCommand;
EXECUTE sp_executesql #sqlCommand
FETCH NEXT FROM c1
INTO #dbname
END
CLOSE c1
DEALLOCATE c1
select * from ##temp

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

suggest a query to in sql to find the unused tables

SNAHi
anyone please suggest a query in sql to find the unused tables.
I have a legacy application migrated to .net from coldfusion.But lots of tables are unused now
What is the best way to find all the unused objects from database. (sql 2005)
thanks
SNA
In SQL Server, the acutal table data IS the clustered index. Using this query on the Dynamic Management Views (DMV) in SQL Server 2005 and up, you can find unused indices - if you find any clustered index (index_id=1) being unused over an extended period of time, the table is not being used anymore:
DECLARE #dbid INT
SELECT #dbid = DB_ID(DB_NAME())
SELECT
OBJECTNAME = OBJECT_NAME(I.OBJECT_ID),
INDEXNAME = I.NAME,
I.INDEX_ID
FROM
SYS.INDEXES I
JOIN
SYS.OBJECTS O ON I.OBJECT_ID = O.OBJECT_ID
WHERE
OBJECTPROPERTY(O.OBJECT_ID, 'IsUserTable') = 1
AND I.INDEX_ID NOT IN
(SELECT S.INDEX_ID
FROM SYS.DM_DB_INDEX_USAGE_STATS S
WHERE S.OBJECT_ID = I.OBJECT_ID
AND I.INDEX_ID = S.INDEX_ID
AND DATABASE_ID = #dbid)
ORDER BY
OBJECTNAME,
I.INDEX_ID,
INDEXNAME ASC
Another option would be to temporarily rename a table if you suspect it's not being used, and then see if your app(s) still work as expected. If they do for e.g. 30 days or so, then you're pretty sure you don't need that table anymore.
Marc
-- Query to find the tables not used by any stored procedure, function nor view
-- Using SQL 2005 system tables, all programatical objects for dependencies, and one&only query:
select tables.name, progr.name
from sys.objects tables (nolock)
left join sys.syscomments comm (nolock) on comm.text like '%' + tables.name +'%'
left join sys.objects progr (nolock) on progr.object_id = comm.id and progr.type in ('P', 'FN', 'TR', 'V' )
where tables.type = 'U'
and comm.id is null
Here is a query i have written to find the tables not used by any store procedures..
......................................................................................
Declare #tablename nvarchar(40)
Declare tablecursor cursor for
Select name from sysobjects where xtype = 'U'
DECLARE #sqlCommand nvarchar(1000)
declare #rowCount int
DECLARE #searchstring varchar(50)
DECLARE #ParmDefinition nvarchar(500);
create table #temp
(
UnusedTables nvarchar(40)
)
open tablecursor
fetch next from tablecursor into #tablename
while ##fetch_status = 0
begin
set #searchstring='p'
SET #sqlCommand = N'SELECT #rows = count(o.name) from sysobjects o ,
syscomments c where o.type='+char(39)+#searchstring + char(39)+' and
o.id=c.id and c.text like '+ char(39)+'%' + #tablename +'%'+char(39);
SET #ParmDefinition = N'#rows int OUTPUT';
EXECUTE sp_executesql #sqlCommand, #ParmDefinition,#rows=#rowCount OUTPUT;
if #rowCount = 0
begin
insert into #temp values (#tablename)
end
fetch next from tablecursor into #tablename
end
close tablecursor
deallocate tablecursor
select UnusedTables from #temp
drop table #temp
thanks
SA
Try something like below
DECLARE #TableNameTemp TABLE
(
id INT IDENTITY (1, 1),
tablename VARCHAR(1000)
)
INSERT INTO #TableNameTemp
SELECT table_name
FROM information_schema.tables
WHERE table_type = 'BASE TABLE'
ORDER BY table_name
DECLARE #CursorTestID INT = 1;
DECLARE #TotalCount INT = (SELECT Count(1)
FROM #TableNameTemp)
DECLARE #FinalResult TABLE
(
unsedtables VARCHAR(max)
)
DECLARE #TemExecInsert TABLE
(
testvalue VARCHAR(max),
type VARCHAR(max)
)
DECLARE #TableaName VARCHAR(max) = ''
WHILE #CursorTestID <= #TotalCount
BEGIN
DELETE FROM #TemExecInsert
SET #TableaName = (SELECT tablename
FROM #TableNameTemp
WHERE id = #CursorTestID)
INSERT INTO #TemExecInsert
EXEC Sp_depends
#objname = #TableaName
SET #CursorTestID = #CursorTestID + 1
IF ( (SELECT Count(1)
FROM #TemExecInsert) = 0 )
BEGIN
INSERT INTO #FinalResult
VALUES (#TableaName)
END
END
SELECT *
FROM #FinalResult
PS: Sorry, I am not certain how to bring the answer in shape. Hope this helps

Resources