Truncate tables in databases T-SQL stored procedure - sql

I am planning to write a stored procedure in T-SQL to truncate the tables in a specific database and schema.
The idea is to store all the table names in a table. The table has got 4 columns, those are database name, schema name, table name and flag.
If the flag value is set 0, then the stored procedure should truncate all those tables.
Can anybody give some insight on this?

Suppose you have a table called #tables where you store the details of the tables to be truncated, You can use the following logic/cursor inside your stored procedure to Truncate these tables.
Table Holding Tables Info
DECLARE #Tables TABLE (DBName SYSNAME , SchemaName SYSNAME
,TableName SYSNAME, Flag INT);
INSERT INTO #Tables VALUES
('TestDB' , 'dbo', 'TestTable1', 0),
('TestDB' , 'dbo', 'TestTable2', 0),
('TestDB' , 'dbo', 'TestTable3', 1)
Stored Procedure Code
Declare #DB SYSNAME
, #Schema SYSNAME
, #Table SYSNAME
, #Sql VARCHAR(MAX);
Declare Cur CURSOR LOCAL FAST_FORWARD FOR
SELECT DBName , SchemaName , TableName
FROM #Tables
WHERE Flag = 0
OPEN Cur
FETCH NEXT FROM Cur INTO #DB , #Schema , #Table
WHILE (##FETCH_STATUS = 0)
BEGIN
SET #Sql = N'TRUNCATE TABLE '
+ QUOTENAME (#DB) + '.' + QUOTENAME (#Schema) + '.' + QUOTENAME (#Table)
Exec sp_executesql #Sql
FETCH NEXT FROM Cur INTO #DB , #Schema , #Table
END
CLOSE Cur
DEALLOCATE Cur

Perhaps something like this
Declare #Table table (dbname varchar(50),schem varchar(50),tablename varchar(50),flag bit)
Insert into #Table (dbname,schem,tablename,flag) values
('dbName1','dbo','MyTable1',0),
('dbName2','dbo','MyTableA',1),
('dbName1','dbo','MyTableB',0),
('dbName2','dbo','MyTableZ',1),
('dbName1','dbo','MyTable2',0)
Declare #SQL varchar(max) = ''
Select #SQL = coalesce(#SQL,' ') + ';truncate table [' +dbname +'].[' + schem +'].[' + tablename +']'
From #Table
Where Flag=1
Select #SQL
--Exec(#SQL)

Related

Stored procedure to drop the column in SQL Server

I created many tables and I have noticed that I have created one useless column in all the tables. I want to create a stored procedure which will drop one specific column and can be useful in all the column.
I created this stored procedure but I'm getting an error. Help me please
You cannot parametrize table and column names with parameters - those are only valid for values - not for object names.
If this is a one-time operation, the simplest option would be to generate the ALTER TABLE ... DROP COLUMN ... statements in SSMS using this code:
SELECT
'ALTER TABLE ' + SCHEMA_NAME(t.schema_id) + '.' + t.Name +
' DROP COLUMN Phone;'
FROM
sys.tables t
and then execute this code in SSMS; the output from it is a list of statement which you can then copy & paste to a new SSMS window and execute.
If you really want to do this as a stored procedure, you can apply the same basic idea - and then just use code (a cursor) to iterate over the commands being generated, and executing them - something like this:
CREATE PROCEDURE dbo.DropColumnFromAllTables (#ColumnName NVARCHAR(100))
AS
BEGIN
DECLARE #SchemaName sysname, #TableName sysname
-- define cursor over all tables which contain this column in question
DECLARE DropCursor CURSOR LOCAL FAST_FORWARD
FOR
SELECT
SchemaName = s.Name,
TableName = t.Name
FROM
sys.tables t
INNER JOIN
sys.schemas s ON t.schema_id = s.schema_id
WHERE
EXISTS (SELECT * FROM sys.columns c
WHERE c.object_id = t.object_id
AND c.Name = #ColumnName);
-- open cursor and start iterating over the tables found
OPEN DropCursor
FETCH NEXT FROM DropCursor INTO #SchemaName, #TableName
WHILE ##FETCH_STATUS = 0
BEGIN
DECLARE #Stmt NVARCHAR(1000)
-- generate the SQL statement
SET #Stmt = N'ALTER TABLE [' + #SchemaName + '].[' + #TableName + '] DROP COLUMN [' + #ColumnName + ']';
-- execute that SQL statement
EXEC sp_executeSql #Stmt
FETCH NEXT FROM DropCursor INTO #SchemaName, #TableName
END
CLOSE DropCursor
DEALLOCATE DropCursor
END
This procedure should work.
It loops through all cols and then deletes the column where sum(col) is zero.
Take a Backup of the Table
alter procedure deletecolumnsifzero #tablename varchar(1000)
as
set nocount on
declare #n int
declare #sql nvarchar(1000)
declare #sum_cols nvarchar(1000)
declare #c_id nvarchar(100)
set #n = 0
declare c1 cursor for
select column_name from information_schema.columns
where
table_name like #tablename
--Cursor Starts
open c1
fetch next from c1
into #c_id
while ##fetch_status = 0
begin
set #sql=''
set #sql='select #sum_cols = sum('+#c_id+') from ['+#tablename+']'
exec sp_Executesql #sql,N'#sum_cols int out,#tablename nvarchar(100)',#sum_cols out,#tablename
if(#sum_cols = 0)
begin
set #n=#n+1
set #sql=''
set #sql= #sql+'alter table ['+#tablename+'] drop column ['+#c_id+']'
exec sp_executesql #sql
end
fetch next from c1
into #c_id
end
close c1
deallocate c1

SQL query to find all references of a particular column in a database?

I need to write some SQL to find all references of a particular column in a database. The column that I'm trying to find references to exists in a different databases. I've found a few examples of finding references of a column that exist in the same database:
In SQL Server, how can I find everywhere a column is referenced?
But I'm having problems figuring out how to do this for a column that exists in a different database. Can you provide the SQL for this? For example purposes, let's refer to the external column I'm trying to find as:
MyExternalDB.MyExternalSchema.MyExternalTable.MyExternalColumn
Ok, just run this and make sure you set your ColumnName variable
USE [master];
GO
IF OBJECT_ID('tempdb..#columns') IS NOT NULL
DROP TABLE #columns;
GO
CREATE TABLE #columns
( databaseName nvarchar(MAX),
columnid int,
columnName nvarchar(MAX),
objectid int,
objectName nvarchar(MAX));
DECLARE #databaseName sysname;
DECLARE #columnName nvarchar(MAX) = 'ColumnName';
DECLARE cur CURSOR LOCAL FORWARD_ONLY STATIC FOR
SELECT [name]
FROM [sys].[databases]
WHERE [state] = 0
AND [name] NOT IN ( 'tempdb', 'master', 'msdb', 'model' );
OPEN cur;
FETCH NEXT FROM cur
INTO #databaseName;
WHILE ( ##FETCH_STATUS != -1 )
BEGIN;
IF ( ##FETCH_STATUS != -2 )
BEGIN;
DECLARE #statement nvarchar(MAX);
SET #statement =N'Use '+ #databaseName +
N';
if EXISTS (SELECT name FROM sys.[columns] WHERE name = ''' + #columnName + ''')
BEGIN;
INSERT [#columns] ( [databaseName], [columnid], [columnName], [objectid], [objectName] )
SELECT ''' + #databaseName + N''',
c.[column_id],
c.[name],
o.[object_id],
o.[name]
FROM sys.[columns] c
INNER JOIN sys.[objects] o
ON [o].[object_id] = [c].[object_id]
WHERE c.[name] = ''' + #columnName + ''';
END;';
EXEC [sys].[sp_executesql] #stmt = #statement;
END;
FETCH NEXT FROM cur
INTO #databaseName;
END;
CLOSE cur;
DEALLOCATE cur;
SELECT * FROM [#columns];

Getting a table name in a Stored Procedure and using it later [duplicate]

I am trying to execute this query:
declare #tablename varchar(50)
set #tablename = 'test'
select * from #tablename
This produces the following error:
Msg 1087, Level 16, State 1, Line 5
Must declare the table variable "#tablename".
What's the right way to have the table name populated dynamically?
For static queries, like the one in your question, table names and column names need to be static.
For dynamic queries, you should generate the full SQL dynamically, and use sp_executesql to execute it.
Here is an example of a script used to compare data between the same tables of different databases:
Static query:
SELECT * FROM [DB_ONE].[dbo].[ACTY]
EXCEPT
SELECT * FROM [DB_TWO].[dbo].[ACTY]
Since I want to easily change the name of table and schema, I have created this dynamic query:
declare #schema sysname;
declare #table sysname;
declare #query nvarchar(max);
set #schema = 'dbo'
set #table = 'ACTY'
set #query = '
SELECT * FROM [DB_ONE].' + QUOTENAME(#schema) + '.' + QUOTENAME(#table) + '
EXCEPT
SELECT * FROM [DB_TWO].' + QUOTENAME(#schema) + '.' + QUOTENAME(#table);
EXEC sp_executesql #query
Since dynamic queries have many details that need to be considered and they are hard to maintain, I recommend that you read: The curse and blessings of dynamic SQL
Change your last statement to this:
EXEC('SELECT * FROM ' + #tablename)
This is how I do mine in a stored procedure. The first block will declare the variable, and set the table name based on the current year and month name, in this case TEST_2012OCTOBER. I then check if it exists in the database already, and remove if it does. Then the next block will use a SELECT INTO statement to create the table and populate it with records from another table with parameters.
--DECLARE TABLE NAME VARIABLE DYNAMICALLY
DECLARE #table_name varchar(max)
SET #table_name =
(SELECT 'TEST_'
+ DATENAME(YEAR,GETDATE())
+ UPPER(DATENAME(MONTH,GETDATE())) )
--DROP THE TABLE IF IT ALREADY EXISTS
IF EXISTS(SELECT name
FROM sysobjects
WHERE name = #table_name AND xtype = 'U')
BEGIN
EXEC('drop table ' + #table_name)
END
--CREATES TABLE FROM DYNAMIC VARIABLE AND INSERTS ROWS FROM ANOTHER TABLE
EXEC('SELECT * INTO ' + #table_name + ' FROM dbo.MASTER WHERE STATUS_CD = ''A''')
Use:
CREATE PROCEDURE [dbo].[GetByName]
#TableName NVARCHAR(100)
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
DECLARE #sSQL nvarchar(500);
SELECT #sSQL = N'SELECT * FROM' + QUOTENAME(#TableName);
EXEC sp_executesql #sSQL
END
You can't use a table name for a variable. You'd have to do this instead:
DECLARE #sqlCommand varchar(1000)
SET #sqlCommand = 'SELECT * from yourtable'
EXEC (#sqlCommand)
You'll need to generate the SQL content dynamically:
declare #tablename varchar(50)
set #tablename = 'test'
declare #sql varchar(500)
set #sql = 'select * from ' + #tablename
exec (#sql)
Use sp_executesql to execute any SQL, e.g.
DECLARE #tbl sysname,
#sql nvarchar(4000),
#params nvarchar(4000),
#count int
DECLARE tblcur CURSOR STATIC LOCAL FOR
SELECT object_name(id) FROM syscolumns WHERE name = 'LastUpdated'
ORDER BY 1
OPEN tblcur
WHILE 1 = 1
BEGIN
FETCH tblcur INTO #tbl
IF ##fetch_status <> 0
BREAK
SELECT #sql =
N' SELECT #cnt = COUNT(*) FROM dbo.' + quotename(#tbl) +
N' WHERE LastUpdated BETWEEN #fromdate AND ' +
N' coalesce(#todate, ''99991231'')'
SELECT #params = N'#fromdate datetime, ' +
N'#todate datetime = NULL, ' +
N'#cnt int OUTPUT'
EXEC sp_executesql #sql, #params, '20060101', #cnt = #count OUTPUT
PRINT #tbl + ': ' + convert(varchar(10), #count) + ' modified rows.'
END
DEALLOCATE tblcur
You need to use the SQL Server dynamic SQL:
DECLARE #table NVARCHAR(128),
#sql NVARCHAR(MAX);
SET #table = N'tableName';
SET #sql = N'SELECT * FROM ' + #table;
Use EXEC to execute any SQL:
EXEC (#sql)
Use EXEC sp_executesql to execute any SQL:
EXEC sp_executesql #sql;
Use EXECUTE sp_executesql to execute any SQL:
EXECUTE sp_executesql #sql
Declare #tablename varchar(50)
set #tablename = 'Your table Name'
EXEC('select * from ' + #tablename)
Also, you can use this...
DECLARE #SeqID varchar(150);
DECLARE #TableName varchar(150);
SET #TableName = (Select TableName from Table);
SET #SeqID = 'SELECT NEXT VALUE FOR ' + #TableName + '_Data'
exec (#SeqID)
Declare #fs_e int, #C_Tables CURSOR, #Table varchar(50)
SET #C_Tables = CURSOR FOR
select name from sysobjects where OBJECTPROPERTY(id, N'IsUserTable') = 1 AND name like 'TR_%'
OPEN #C_Tables
FETCH #C_Tables INTO #Table
SELECT #fs_e = sdec.fetch_Status FROM sys.dm_exec_cursors(0) as sdec where sdec.name = '#C_Tables'
WHILE ( #fs_e <> -1)
BEGIN
exec('Select * from ' + #Table)
FETCH #C_Tables INTO #Table
SELECT #fs_e = sdec.fetch_Status FROM sys.dm_exec_cursors(0) as sdec where sdec.name = '#C_Tables'
END

SQL Server look for stored procedure

I'm using SQL Server Management Studio and I have multiple server connections and I need to know where a specific stored procedure exists in every server which contains multiple databases!
Looking for a query to run on each server
Here is a little script that you could run on each server.
I know that it uses a while loop, which is generally not preferred, someone might be able to improve on it.
Run the script from the master database.
SQL Query:
set nocount on
declare #procname varchar(150) = '<SPROCNAME_TO_FIND>' -- SET THIS TO THE STORED PROCEDURE NAME YOU ARE LOOKING FOR
declare #alldbonserver table
( databasename varchar(150),
doneflag bit )
declare #foundtbl table
( countcol int,
dbname varchar(150) )
declare #errortbl table
( dbname varchar(150) )
insert #alldbonserver
( databasename,
doneflag )
select sdb.name,
0
from sys.databases sdb
declare #curdbname varchar(150),
#sqlcmd varchar(max)
while exists (select 1
from #alldbonserver
where doneflag = 0)
begin
select top 1
#curdbname = databasename
from #alldbonserver
where doneflag = 0
select #sqlcmd = 'select distinct 1, ''' + #curdbname + ''' as dbname from ' + #curdbname + '.sys.objects where type = ''P'' and name = ''' + #procname + ''''
begin try
insert #foundtbl
( countcol, dbname )
exec(#sqlcmd)
end try
begin catch
insert #errortbl
values ( #curdbname )
end catch
update #alldbonserver
set doneflag = 1
where databasename = #curdbname
end
select dbname as 'Databases with stored procedure'
from #foundtbl
select dbname as 'Unable to access databases'
from #errortbl
set nocount off
Sample output:
Databases with stored procedure
-----------------------------------------
MainDatabase
SomeOtherDatabase
Unable to access databases
-----------------------------------------
model
ReportServer$SQLTemp
VeryPrivateDatabase
If you are using SSMS, you could create a server registration group that contains all of the servers you connect to, right click on the group and run this query against the group: exec sp_MSforeachdb 'select * from [?].sys.procedures where name=''<your_name_here>'''
This query will enumerate each of the databases on each of the servers in the group (note: the single quotes are like that for a reason...)
I just put this together on SQL2012. It should return all Stored Procs on a Server for a given name. If you leave #SPName blank, you will get all of them.
The Query utilizes sys.all_objects so you could easily change it to work the same for tables, functions, any or all db objects.
DECLARE #SPName VARCHAR(256)
SET #SPName = 'My_SP_Name'
DECLARE #DBName VARCHAR(256)
DECLARE #varSQL VARCHAR(512)
DECLARE #getDBName CURSOR
SET #getDBName = CURSOR FOR
SELECT name
FROM sys.databases
CREATE TABLE #TmpTable (DBName VARCHAR(256),
SchemaName VARCHAR(256),
SPName VARCHAR(256))
OPEN #getDBName
FETCH NEXT
FROM #getDBName INTO #DBName
WHILE ##FETCH_STATUS = 0
BEGIN
SET #varSQL = 'USE [' + #DBName + '];
INSERT INTO #TmpTable
SELECT '''+ #DBName + ''' AS DBName,
SCHEMA_NAME(schema_id) AS SchemaName,
name AS SPName
FROM sys.all_objects
WHERE [type] = ''P'' AND name LIKE ''%' + #SPName + '%'''
EXEC (#varSQL)
FETCH NEXT
FROM #getDBName INTO #DBName
END
CLOSE #getDBName
DEALLOCATE #getDBName
SELECT *
FROM #TmpTable
DROP TABLE #TmpTable

SQL: Creating In-Line Table Function inside Cursor

I am trying to run an SQL script that will create a function on each of my databases and then use that function to populate a temporary table, which is then used as the source for another cursor that is used to rebuild indexes. however, the problem I have is that the function is only be created on the Database to which I am currently connected, even though I'm using 'Use Database' in my cursor. I have copied the script below, which has been written as to isolate the issue (so it isn't efficient yet).
IF OBJECT_ID (N'sp_index_maintenance', N'P') IS NOT NULL
DROP Proc sp_index_maintenance;
GO
Create proc sp_index_maintenance
AS
BEGIN
CREATE TABLE #T1
(
Database_Name NVARCHAR(MAX),
[Object_Name] NVARCHAR(MAX),
Index_Name NVARCHAR(MAX),
Index_ID INT,
Index_Type_Desc NVARCHAR(MAX),
AVG_Fragmentation_in_percent INT,
Fragment_Count INT,
Page_Count INT
)
DECLARE #DB as nvarchar(100);
DECLARE #Command as NVARCHAR(MAX);
DECLARE #FetchFragStatus AS NVARCHAR(max);
DECLARE #Create_Function NVARCHAR(Max);
DECLARE #Drop_Function NVARCHAR(MAX);
DECLARE DB_USE cursor for
SELECT [Name] FROM sys.databases
OPEN DB_USE
FETCH NEXT FROM DB_USE
INTO #DB
WHILE ##FETCH_STATUS = 0
BEGIN
SET #Command = 'USE ' + #DB
SET #Drop_Function = 'USE ' + #DB + ' IF OBJECT_ID (N''dbo.Index_fragmentation'', N''IF'') IS NOT NULL
DROP Function dbo.index_fragmentation'
SET #Create_Function =
'Create function dbo.index_fragmentation()
RETURNS TABLE AS
RETURN
(
SELECT
DB_NAME(database_ID) AS Database_Name,
OBJECT_NAME(ps.object_id) as [Object_Name],
i.Name AS Index_Name,
ps.index_id,
index_type_desc,
avg_fragmentation_in_percent,
fragment_count,
page_count
FROM
sys.dm_db_index_physical_stats(DB_ID(), NULL, NULL, NULL, ''Limited'') AS ps
INNER JOIN
sys.indexes AS i WITH (NOLOCK)
ON ps.[object_id] = i.[object_id]
AND ps.index_id = i.index_id
WHERE database_id = DB_ID()
--AND page_count > 500
AND avg_fragmentation_in_percent >= 20)'
PRINT (#command)
EXEC sp_executesql #Command
--PRINT (#Drop_Function)
--EXEC (#Drop_Function)
PRINT (#Create_function)
EXEC sp_executesql #Create_function
FETCH NEXT FROM DB_USE
INTO #DB
END
CLOSE DB_USE
DEALLOCATE DB_USE
DECLARE DB_USE cursor for
SELECT [Name] FROM sys.databases
OPEN DB_USE
FETCH NEXT FROM DB_USE
INTO #DB
WHILE ##FETCH_STATUS = 0
BEGIN
SET #FetchFragStatus = 'USE ' + #DB +
' INSERT INTO #T1 (Database_Name, Object_Name, Index_Name, index_Id, index_type_desc, avg_fragmentation_in_percent, fragment_count, page_count)
SELECT * FROM dbo.Index_Fragmentation()'
PRINT (#FetchFragStatus);
EXEC (#FetchFragStatus);
FETCH NEXT FROM DB_USE
INTO #DB
END
CLOSE DB_USE
DEALLOCATE DB_USE
--DECLARE #DB_Name NVARCHAR(100);
--DECLARE #Index_Name NVARCHAR(100);
--DECLARE #Alter_index NVARCHAR(MAX);
--DECLARE #Obj_Name NVARCHAR(MAX);
--
--DECLARE Fragmented_index_Cur Cursor For
--SELECT Database_Name, Index_Name, [Object_Name]
--FROM #T1
--
--OPEN Fragmented_index_cur
--FETCH NEXT FROM Fragmented_index_cur
--INTO
--#DB_Name, #Index_Name, #Obj_Name
--WHILE ##FETCH_STATUS = 0
--BEGIN
--SET #Command = 'USE ' + #DB_NAME
--SET #Alter_index = 'ALTER Index ' + #Index_Name + ' ON ' + #Obj_Name + ' REBUILD;'
--PRINT (#command)
--EXEC (#command)
--PRINT (#Alter_Index)
--EXEC (#Alter_index)
--
--FETCH NEXT FROM Fragmented_index_cur
--INTO #DB_Name, #Index_Name, #Obj_Name
--
--END
--CLOSE Fragmented_index_cur
--DEALLOCATE Fragmented_index_cur
SELECT * FROM #T1
RETURN;
END
EXEC sp_index_maintenance
Best way to execute your script against all database is to use Microsoft's EXEC sys.sp_MSforeachdb undocumented function, that comes in very handy, if you google you can find a lot of examples of its use. By using this function you can get rid of bad cursors that many people in community will chastise you for. I'm all for use of cursors just need to know when to use them.
here is simplified version of your query. This will get bad indexes in all database and store into temp table.
CREATE PROCEDURE myBadIndexFromAllDBs
AS
BEGIN
CREATE TABLE #tempTable
(
Database_Name VARCHAR(250)
,OBJECT_NAME VARCHAR(250)
,Index_Name VARCHAR(250)
,Index_id INT
,index_type_desc VARCHAR(60)
,avg_fragmentation_in_percent FLOAT
,fragment_count BIGINT
,page_count BIGINT
)
EXEC sys.sp_MSforeachdb
'
use [?]
INSERT INTO #tempTable
SELECT DB_NAME(database_ID) AS Database_Name
,OBJECT_NAME(ps.object_id) AS [Object_Name]
,i.Name AS Index_Name
,ps.index_id
,index_type_desc
,avg_fragmentation_in_percent
,fragment_count
,page_count
FROM sys.dm_db_index_physical_stats(DB_ID(), NULL, NULL, NULL, ''Limited'') AS ps
INNER JOIN sys.indexes AS i WITH ( NOLOCK )
ON ps.[object_id] = i.[object_id]
AND ps.index_id = i.index_id
WHERE database_id = DB_ID()
AND avg_fragmentation_in_percent >= 50
'
SELECT *
FROM #tempTable
END
each sp_executesql is run under it's own instance, so the sp_executesql #Command only puts its call as using the other database.
Try moving the 'USE ' + #DB into the #Create_Function