Run sql query through SQL agent job across all Databases - sql-server

I am trying to run the following query across all databases in one instance through SQL agent job(except master db), which is basically used for index optimization
I have created the agent job but runs through only one database. Help is appreciated. I have attached Agent job, how I have created
USE [DBNAME]
SET NOCOUNT ON
DECLARE #Objectid INT, #Indexid INT,
#schemaname VARCHAR(100), #tablename VARCHAR(300),
#ixname VARCHAR(500),
#avg_fragment float, #command VARCHAR(4000)
DECLARE AWS_Cusrsor CURSOR FOR
SELECT
A.object_id, A.index_id,
QUOTENAME(SS.NAME) AS schemaname,
QUOTENAME(OBJECT_NAME(B.object_id, B.database_id)) AS tablename,
QUOTENAME(A.name) AS ixname,
B.avg_fragmentation_in_percent AS avg_fragment
FROM
sys.indexes A
INNER JOIN
sys.dm_db_index_physical_stats(DB_ID(), NULL, NULL, NULL, 'LIMITED') AS B ON A.object_id = B.object_id
AND A.index_id = B.index_id
INNER JOIN
sys.OBJECTS OS ON A.object_id = OS.object_id
INNER JOIN
sys.schemas SS ON OS.schema_id = SS.schema_id
WHERE
B.avg_fragmentation_in_percent > 30
AND A.index_id > 0
AND A.IS_DISABLED <> 1
ORDER BY
tablename,ixname
OPEN AWS_Cusrsor
FETCH NEXT FROM AWS_Cusrsor INTO #Objectid, #Indexid, #schemaname, #tablename, #ixname, #avg_fragment
WHILE ##FETCH_STATUS = 0
BEGIN
IF #avg_fragment >= 30.0
BEGIN
SET #command = N'ALTER INDEX '+#ixname+N' ON '+#schemaname+N'.'+ #tablename+N' REBUILD '+N' WITH (ONLINE = ON)';
SET #command = N'ALTER INDEX '+#ixname+N' ON '+#schemaname+N'.'+ #tablename+N' REORGANIZE';
END
EXEC(#command)
FETCH NEXT FROM AWS_Cusrsor INTO #Objectid, #Indexid, #schemaname, #tablename, #ixname, #avg_fragment
END
CLOSE AWS_Cusrsor
DEALLOCATE AWS_Cusrsor

Related

Create cursor inside cursor

I am pretty new to the cursor. I am trying to run cursor inside a cursor. Help is appreciated. Context: I am trying to run index_optimize stored procedure through all databases when SQL Server starts.
USE [master]
GO
CREATE PROCEDURE [dbo].[Run_through_database]
AS
BEGIN
DECLARE #DatabaseName AS varchar(500)
-- Provide the name of SP that you want to run
DECLARE #SPName AS varchar(128) = 'dbo.index_optimize'
DECLARE DBCursor CURSOR FOR
--Filter the list of the database in which stored procedure exists
SELECT NAME
FROM sys.databases
WHERE database_id > 4
OPEN DBCursor
FETCH NEXT FROM DBCursor INTO #DatabaseName
WHILE ##FETCH_STATUS = 0
BEGIN
DECLARE #DBName AS nvarchar(500);
SET #DBName = QUOTENAME(N'' + #DatabaseName + '');
-- Use Dynamic SQL to change the database name and
-- execute stored procedure from that database
EXEC (N'USE ' + #DBName + N'; EXEC(''' + #SPName + ' '');'
);
FETCH NEXT FROM DBCursor INTO #DatabaseName
END
CLOSE DBCursor
DEALLOCATE DBCursor
END
USE [master]
GO
ALTER PROCEDURE [dbo].[Index_optimize]
AS
BEGIN
DECLARE #Objectid INT, #Indexid INT,#schemaname VARCHAR(100),#tablename VARCHAR(300),#ixname VARCHAR(500),#avg_fragment float,#command VARCHAR(4000)
DECLARE AWS_Cusrsor CURSOR FOR
SELECT A.object_id,A.index_id,QUOTENAME(SS.NAME) AS schemaname,QUOTENAME(OBJECT_NAME(B.object_id,B.database_id))as tablename ,QUOTENAME(A.name) AS ixname,B.avg_fragmentation_in_percent AS avg_fragment FROM sys.indexes A inner join sys.dm_db_index_physical_stats(DB_ID(),NULL,NULL,NULL,'LIMITED') AS B
ON A.object_id=B.object_id and A.index_id=B.index_id
INNER JOIN SYS.OBJECTS OS ON A.object_id=OS.object_id
INNER JOIN sys.schemas SS ON OS.schema_id=SS.schema_id
WHERE B.avg_fragmentation_in_percent>30 AND A.index_id>0 AND A.IS_DISABLED<>1
ORDER BY tablename,ixname
OPEN AWS_Cusrsor
FETCH NEXT FROM AWS_Cusrsor INTO #Objectid,#Indexid,#schemaname,#tablename,#ixname,#avg_fragment
WHILE ##FETCH_STATUS=0
BEGIN
IF #avg_fragment>=30.0
BEGIN
SET #command=N'ALTER INDEX '+#ixname+N' ON '+#schemaname+N'.'+ #tablename+N' REBUILD '+N' WITH (ONLINE = ON)';
--Can add following line for index reorganization. Else remove following line.
SET #command=N'ALTER INDEX '+#ixname+N' ON '+#schemaname+N'.'+ #tablename+N' REORGANIZE';
EXEC(#command)
PRINT #command
END
FETCH NEXT FROM AWS_Cusrsor INTO #Objectid,#Indexid,#schemaname,#tablename,#ixname,#avg_fragment
END
CLOSE AWS_Cusrsor
DEALLOCATE AWS_Cusrsor
End
GO

Page Level Compression - All Tables

Does anyone know a way to see the Compression level through the Calculate button without having to go through each table 1-by-1?
You can call sp_estimate_data_compression_savings for each table, specifying the desired compression level. Below is an example script that uses a cursor for the task, inserting the results of each table into a table variable and the final results of all tables via a select query.
USE YourDatabase;
SET NOCOUNT ON;
DECLARE #estimated_compression TABLE(
object_name sysname,
schema_name sysname,
index_id int,
partition_number int,
size_with_current_compression_setting_kb bigint,
size_with_requested_compression_setting_kb bigint,
sample_size_with_current_compression_setting_kb bigint,
sample_size_with_requested_compression_setting_kb bigint
);
DECLARE #schema_name sysname, #object_name sysname;
DECLARE tables CURSOR LOCAL FAST_FORWARD READ_ONLY FOR
SELECT s.name AS schema_name, t.name AS table_name
FROM sys.schemas AS s
JOIN sys.tables AS t ON t.schema_id = s.schema_id;
OPEN tables;
WHILE 1 = 1
BEGIN
FETCH NEXT FROM tables INTO #schema_name, #object_name;
IF ##FETCH_STATUS = -1 BREAK;
INSERT INTO #estimated_compression
EXEC sp_estimate_data_compression_savings
#schema_name = #schema_name
, #object_name = #object_name
, #index_id = NULL
, #partition_number = NULL
, #data_compression = 'PAGE';
END
CLOSE tables;
DEALLOCATE tables;
SELECT *
FROM #estimated_compression
ORDER BY object_name, schema_name, index_id, partition_number;
GO

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 get the Index Name from IndexId in SQL Server 2005

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

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