Run operations on all the tables in all the databases - sql-server

I'm trying to create a SQL Server script that applies some operations to all the tables in all the databases. I need to rename some tables if some conditions are respected, truncate the tables otherwise.
This is my script
EXEC sp_MSforeachdb
#command1 = '
IF not exists(select 1 where ''?'' in (''master'',''model'',''msdb'',''tempdb''))
EXEC [?].dbo.sp_MSforeachtable
#command1 = ''
IF(substring(&, 1, 3)=pv_ and right(&, 5) != _data and right(&, 4) != _BCK)
exec sp_RENAME & , &_BCK''
ELSE IF (right(&, 4) != _BCK)
TRUNCATE TABLE &
#replacechar = ''&'''
I got some errors but I'm new to SQL Server and I have not idea how to fix this script.
Any suggestions?
Many thanks

Here is a solution for start. It won't be quick, but it loops all tables of all databases on the server. Inside in the second cursor you can deceide what to do with the table.
(The query is not optimalized, just a quick solution)
DECLARE #DBName NVARCHAR(50)
DECLARE #TableName NVARCHAR(100)
DECLARE #DynamicSQL NVARCHAR(300)
DECLARE #DBCursor CURSOR
SET #DBCursor = CURSOR FOR
SELECT NAME FROM SYS.DATABASES
WHERE NAME NOT IN ('master','tempdb','model','msdb')
OPEN #DBCursor
FETCH NEXT FROM #DBCursor INTO #DBName
WHILE ##FETCH_STATUS = 0
BEGIN
CREATE TABLE #TempTableDatas
(
name varchar(100),
objectID int
)
SET #DynamicSQL = 'INSERT INTO #TempTableDatas
SELECT name, object_id FROM [' + #DBName + ']' + '.sys.Tables '
EXEC SP_EXECUTESQL #DynamicSQL
DECLARE #TableCursor CURSOR
SET #TableCursor = CURSOR FOR
SELECT name FROM #TempTableDatas
OPEN #TableCursor
FETCH NEXT FROM #TableCursor INTO #TableName
WHILE ##FETCH_STATUS = 0
BEGIN
SELECT #TableName, #DBName
FETCH NEXT FROM #TableCursor INTO #TableName
END
CLOSE #TableCursor
DEALLOCATE #TableCursor
DROP TABLE #TempTableDatas
FETCH NEXT FROM #DBCursor INTO #DBName
END
CLOSE #DBCursor
DEALLOCATE #DBCursor

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

sql cursor insert result into a table

I have created a cursor which iterates through all the databases and displays the 1 record per database.
I would like the records to be inserted into 1 table where I can view it. The query may change which is why I don't want to create the table structure for a specific query and insert it. I wanted to use the "select into" clause but that will fail on the second time the cursor runs
DECLARE #DB_Name varchar(100)
DECLARE #Command nvarchar(200)
DECLARE database_cursor CURSOR FOR SELECT name FROM #DBNAME
OPEN database_cursor
FETCH NEXT FROM database_cursor INTO #DB_Name
WHILE ##FETCH_STATUS = 0
BEGIN
SELECT #Command = 'use [' + #DB_Name + '] Select '''+ #DB_Name + ''' ,'+
--Enter query below
'* from authentication where username like ''%clair#indicater%'' and password = ''Rohan2410'''
-- print #Command
EXEC sp_executesql #Command
FETCH NEXT FROM database_cursor INTO #DB_Name
END
CLOSE database_cursor
DEALLOCATE database_cursor
You should better use INSERT INTO ... instead of SELECT INTO, something like this:
DECLARE #DB_Name varchar(100)
DECLARE #Command nvarchar(200)
DECLARE database_cursor CURSOR FOR SELECT name FROM #DBNAME
OPEN database_cursor
FETCH NEXT FROM database_cursor INTO #DB_Name
WHILE ##FETCH_STATUS = 0
BEGIN
SELECT #Command = 'use [' + #DB_Name + ']
IF OBJECT_ID(''tempdb..##output'') IS NULL
BEGIN
SELECT NULL AS DB_Name,*
INTO ##output
FROM authentication WHERE 1=0
END
INSERT INTO ##output
Select '''+ #DB_Name + ''' ,'+
--Enter query below
'* from authentication where username like ''%clair#indicater%'' and password = ''Rohan2410'''
-- print #Command
EXEC sp_executesql #Command
FETCH NEXT FROM database_cursor INTO #DB_Name
END
CLOSE database_cursor
DEALLOCATE database_cursor
SELECT * FROM ##output
DROP TABLE ##output
Basically, on the first cursor iteration we will create an empty temp table with the correct structure. Then we just insert into that temp table.

Trying to write some T-SQL to iterate through the DB tables

I am using SQL Server 2008 R2 on dev, and SQL Azure for test and live.
I wish to write a little procedure to reset the identity seeds since SQL Azure does not support DBCC.
I have some workaround code which works, but I do not want to write it out for each table, so was trying to write a routine that iterates through the DB tables.
Tables:
SELECT * FROM information_schema.tables
Code:
delete from TABLE_NAME where Id>150000
GO
SET IDENTITY_INSERT [TABLE_NAME] ON
GO
INSERT INTO [TABLE_NAME](Id) VALUES(150000)
GO
delete from TABLE_NAME where Id=150000
GO
SET IDENTITY_INSERT [TABLE_NAME] OFF
GO
I guess I need to wrap this in a loop. Sorry my T-SQL is not that strong, hence the request for help.
Also it would be helpful to omit all tables with TABLE_NAME starting with aspnet_ and use only TABLE_TYPE = "BASE TABLE"
Any help hugely appreciated.
Unless somebody else knows a trick that I don't, you're probably stuck using dynamic SQL and iterating through a list of table names using either a cursor or a temporary table. The cursor approach would look something like this:
declare #TableName nvarchar(257);
declare #sql nvarchar(max);
declare TableCursor cursor read_only for
select
TABLE_SCHEMA + '.' + TABLE_NAME
from
INFORMATION_SCHEMA.TABLES
where
TABLE_NAME not like 'aspnet\_%' escape '\' and
TABLE_TYPE = 'BASE TABLE';
open TableCursor;
fetch next from TableCursor into #TableName;
while ##fetch_status = 0
begin
set #sql = 'select top 1 * from ' + #TableName;
exec sp_executesql #sql;
fetch next from TableCursor into #TableName;
end
close TableCursor;
deallocate TableCursor;
You can read more about cursors here. Alternatively, you could do it with an in-memory table like this:
declare #Tables table (RowId int identity(1, 1), TableName nvarchar(257));
declare #TableName nvarchar(257);
declare #Index int;
declare #TableCount int;
declare #sql nvarchar(max);
insert into #Tables (TableName)
select
TABLE_SCHEMA + '.' + TABLE_NAME
from
INFORMATION_SCHEMA.TABLES
where
TABLE_NAME not like 'aspnet\_%' escape '\' and
TABLE_TYPE = 'BASE TABLE';
set #TableCount = ##rowcount;
set #Index = 1
while #Index <= #TableCount
begin
select #TableName = TableName from #Tables where RowId = #Index;
set #sql = 'select top 1 * from ' + #TableName;
exec sp_executesql #sql;
set #Index = #Index + 1;
end
In the interest of brevity, my examples use a much simpler SQL statement than yours—I'm just selecting one record from each table—but this ought to be enough to illustrate how you can get this done.

Can I apply an update statement to multiple databases at the same time?

Say I want to run the following:
update users set age = 10
on databases:
db1, db2, db3
All on the same server, I want to loop through and perform the same action.
Currently I am doing this manually using management studio via the dropdown.
Hoping there is a better way.
You could probably do it with dynamic SQL. Something like so:
create table #dbs (db_name sysname not null)
insert into #dbs values ('db1'),('db2'),('db3')
declare curs cursor for
select db_name from #dbs
declare #db sysname, #sql nvarchar(max)
open curs
while(1=1)
begin
fetch next from curs into #db
if (##fetch_status <> 0)
break
set #sql = 'update ' + quotename(#db) + '.dbo.users set age = 10'
exec(#sql)
end
close curs
deallocate curs
drop table #dbs
Not sure about doing it 'dynamically', i.e. a FOR-EACH style loop on all the databases in a server, but this should work:
USE db1
update users set age = 10
GO
USE db2
update users set age = 10
GO
USE db3
update users set age = 10
Designate a server as a central management server and then add the other servers to the server group. Then you can run the update on all databases within the group. http://msdn.microsoft.com/en-us/library/bb934126.aspx
use [WWAUTHxxx__] -- a db containing active databases.
set nocount on
declare #Catalog as nvarchar(32)
declare #LibraryName as varchar(255)
declare #dbtable as varchar(50)
declare #retval as nvarchar(50)
declare #sSQL as nvarchar(max)
declare #parmdef as nvarchar(500)
declare #retvalout as nvarchar(50)
Declare Library_Cursor Cursor for
select top(1000) xCatalog, xLibraryName
from Active_DBs
order by xcatalog
Open Library_Cursor;
Fetch Next from Library_Cursor into #Catalog, #LibraryName
while ##Fetch_status = 0
begin
set #dbTable = #Catalog + '.dbo.las_circperiods'
set #ParmDef = N'#retvalOUT int OUTPUT';
set #sSQL = N'Select #retvalout = count(*) from ' + #dbtable
+ ' where xlastcircdate is null'
exec sp_executesql #ssql,#parmdef,#retvalout=#retval output
if #retval > 0 -- check/print Sql and then activate.
-- I like checking to see the potentially affected databases.
begin
print #Catalog + ',' + #LibraryName + ',' + #retval
set #ssql = N'update ' + #dbTable
+ ' set xlastcircdate = '''' '
+ ' where xlastcircdate is null'
-- print #ssql -- View what you might will do
exec sp_executesql #ssql -- Do it.
end
Fetch Next from Library_Cursor into #Catalog, #LibraryName
end;
close Library_cursor
Deallocate Library_cursor

How can I drop all the default constraints constraints on a table

How can I drop all the default constraints belonging to a particular table in SQL 2005?
One solution from a search: (Edited for Default constraints)
SET NOCOUNT ON
DECLARE #constraintname SYSNAME, #objectid int,
#sqlcmd VARCHAR(1024)
DECLARE CONSTRAINTSCURSOR CURSOR FOR
SELECT NAME, object_id
FROM SYS.OBJECTS
WHERE TYPE = 'D' AND #objectid = OBJECT_ID('Mytable')
OPEN CONSTRAINTSCURSOR
FETCH NEXT FROM CONSTRAINTSCURSOR
INTO #constraintname, #objectid
WHILE (##FETCH_STATUS = 0)
BEGIN
SELECT #sqlcmd = 'ALTER TABLE ' + OBJECT_NAME(#objectid) + ' DROP CONSTRAINT ' + #constraintname
EXEC( #sqlcmd)
FETCH NEXT FROM CONSTRAINTSCURSOR
INTO #constraintname, #objectid
END
CLOSE CONSTRAINTSCURSOR
DEALLOCATE CONSTRAINTSCURSOR
I know this is old, but I just found it when googling.
A solution that works for me in SQL 2008 (not sure about 2005) without resorting to cursors is below :
declare #sql nvarchar(max)
set #sql = ''
select #sql = #sql + 'alter table YourTable drop constraint ' + name + ';'
from sys.default_constraints
where parent_object_id = object_id('YourTable')
AND type = 'D'
exec sp_executesql #sql
Script posted by gbn does not work for me, so I'm using a modified version:
SET NOCOUNT ON
DECLARE #DfId INT, #TableId INT,
#SqlCmd VARCHAR(1024)
DECLARE DFCONSTRAINTCUR CURSOR FOR
SELECT [parent_object_id] TABLE_ID, [object_id] DF_ID
FROM SYS.OBJECTS
where parent_object_id = OBJECT_ID('<table name>')
and [TYPE] = 'D'
OPEN DFCONSTRAINTCUR
FETCH NEXT FROM DFCONSTRAINTCUR
INTO #TableId, #DfId
WHILE (##FETCH_STATUS = 0)
BEGIN
SELECT #sqlcmd = 'ALTER TABLE ' + OBJECT_NAME(#TableId) + ' DROP CONSTRAINT ' + OBJECT_NAME(#DfId)
EXEC(#sqlcmd)
FETCH NEXT FROM DFCONSTRAINTCUR
INTO #TableId, #DfId
END
CLOSE DFCONSTRAINTCUR
DEALLOCATE DFCONSTRAINTCUR
Just why do you want to do this? Dropping constraints is a pretty drastic action and affects all users not just your process. Maybe your problem can be solved some other way. If you aren't the dba of the system, you should think very hard about whether you should do this. (Of course in most systems, a dba wouldn't allow anyone else the permissions to do such a thing.)

Resources