Pass Column Name as parameter - c#

I want to PassColumn name as a paremeter in My SP
And if my tat column exists in first table (Batch_Master), want to fatch value from that column,
And if that column exists in my second table (GTIN_Master), want to fetch value from tat table column,
Each table have columns like..
Batch_Master (Batch_M_id, GTIN(primary key),....etc
GTIN_Master (GTIN (foreign key),..etc)
I have Batch_M_id, and column name as a parameter..
Note: column Name having random datatype, some time int or some time datetime etc
I Try followin SP
CREATE PROCEDURE dbo.StoredProcedure2
#columnName varchar(50),
#batchmId int
AS
if exists(select * from sys.columns
where Name = N'columnName' and Object_ID = Object_ID(NBatch_Master'))
begin
select #columnName from Batch_Master
end
else
begin
select #columnName
from GTIN_Master inner join Batch_Master
on GTIN_Master.GTIN = Batch_Master.GTIN
where Batch_M_id =#batchmId
end
RETURN

What you need when you do not know exactly the query structure you are going to execute, then you have to create a dynamic query, which is actually a form of templating queries.
CREATE PROCEDURE dbo.StoredProcedure2
#columnName varchar(50),
#batchmId int
AS
DECLARE #SQL1 AS VARCHAR(MAX)
DECLARE #SQL2 AS VARCHAR(MAX)
SET #SQL1 = 'select ' + #columnName + ' from Batch_Master'
SET #SQL1 = 'select ' + #columnName + '
from GTIN_Master inner join Batch_Master
on GTIN_Master.GTIN = Batch_Master.GTIN
where Batch_M_id =' + CONVERT(VARCHAR,#batchmId)
IF EXISTS(SELECT * FROM sys.columns WHERE Name = #columnName and Object_ID = Object_ID(N'Batch_Master'))
BEGIN
EXEC (#SQL1)
END
ELSE
BEGIN
EXEC (#SQL2)
END
The above will do what you want but is prone to errors. For instance what if the column passed in the parameter does not exist in the tables used in the second query? You should probably need to check for existence in the second case too.

DECLARE #SQL VARCHAR(MAX)
SET #SQL = 'select ' + #columnName + ' from Batch_Master'
EXECUTE(#SQL)

This SQL:
set nocount on
go
create table One (id int, name varchar(25))
go
create table Two (id int, value varchar(25))
go
insert into One values (1, 'Table One')
insert into Two values (1, 'Table Two')
go
create procedure sp_test_colname
#colname sysname
as
declare #sql nvarchar(2048)
if exists (select 1 from sys.columns where name = #colname and object_id = object_id(N'One'))
set #sql = 'select [' + #colname + '] from [One]'
else
if exists (select 1 from sys.columns where name = #colname and object_id = object_id(N'Two'))
set #sql = 'select [' + #colname + '] from [Two]'
if #sql <> ''
exec sp_executesql #sql
go
exec sp_test_colname 'name'
exec sp_test_colname 'value'
exec sp_test_colname 'somethingelse'
go
drop procedure sp_test_colname
drop table One, Two
Returns the following:
name
-------------------------
Table One
value
-------------------------
Table Two

Related

Conversion failed when converting the varchar value ' AND ID =' to data type int

I was looking how I can parameterize table names and so I found dynamic sql queries. I finally got the proc saved, but when I execute it errors out with "Conversion failed when converting the varchar value ' AND ID =' to data type int." I have no idea what is going wrong when I try to execute this stored proc. I feel like it must be a typo but I cannot tell. The stored pro.
EDITED to incorporate the suggestion below. Still no luck unless I am doing this wrong.
-- =======================================================
-- Create Stored Procedure Template for Azure SQL Database
-- =======================================================
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
-- =============================================
-- Author: <Author, , Name>
-- Create Date: <Create Date, , >
-- Description: <Description, , >
-- =============================================
ALTER PROCEDURE [dbo].[sp_GetFormFieldCDC]
(
#formfieldId INT,
#C___operation INT,
#C___start_lsn binary(10),
#tablename NVarchar(255)
)
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON
DECLARE #ActualTableName AS NVarchar(255)
SELECT #ActualTableName = QUOTENAME( TABLE_NAME )
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_NAME = #tablename
DECLARE #sql AS NVARCHAR(MAX)
SELECT #sql = 'SELECT * FROM ' + #ActualTableName + ' WHERE __$start_lsn =' + CONVERT(NVARCHAR(255),#C___start_lsn) + ' AND __$operation =' + #C___operation + ' AND ID =' + #formfieldId + ';'
-- Insert statements for procedure here
EXEC sp_executesql #SQL, N' #formfieldId INT,
#C___operation INT,
#C___start_lsn binary(10),
#tablename NVarchar(255)', #formfieldId ,
#C___operation,
#C___start_lsn,
#tablename
END
GO
You should pass the parameters all the way through to sp_executesql. Do not inject them, unless they are object names, in which case you need QUOTENAME.
You can also use OBJECT_ID to check for table existence, and throw an exception if there is no such object.
CREATE OR ALTER PROCEDURE [dbo].[GetFormFieldCDC]
(
#formfieldId INT,
#C___operation INT,
#C___start_lsn binary(10),
#schemaname sysname,
#tablename sysname
)
AS
SET NOCOUNT ON;
IF (OBJECT_ID(QUOTENAME(#schemaname) + '.' + QUOTENAME(#tablename)) IS NULL)
THROW 50000, 'Table not found', 0;
DECLARE #sql AS NVARCHAR(MAX) = '
SELECT *
FROM ' + QUOTENAME(#schemaname) + '.' + QUOTENAME(#tablename) + '
WHERE __$start_lsn = #C___start_lsn
AND __$operation = #C___operation
AND ID = #formfieldId;
';
EXEC sp_executesql #SQL,
N' #formfieldId INT,
#C___operation INT,
#C___start_lsn binary(10)',
#formfieldId = #formfieldId,
#C___operation = #C___operation,
#C___start_lsn = #C___start_lsn;
GO

EF 6 Merge records and update all dependant FKs programmatically

I want to be able to merge duplicate records in 1 table, and update all child entities whose FK was the originalRecordId to the destinyRecordId. This could be done manually, but it would be a daunting task as the parent table could have 40+ relationships, and this has to be done in multiple parent tables. I am using EF 6 with code first.
I have been able to get all navigation properties using the following (credit goes to #zev-spits in this question):
public List<PropertyInfo> GetNavigationProperties(T entity)
{
var t = entity.GetType();
var elementType = ((IObjectContextAdapter)context).ObjectContext.CreateObjectSet<T>().EntitySet.ElementType;
return elementType.NavigationProperties.Select(np => entityType.GetProperty(np.Name)).ToList();
}
I have no idea where to go from here.
Is there a way to programmatically do this task? I would like to pass in a originalRecord and a destinyRecord, obtain all related entities of the originalRecord and update the FK with the destinyRecordId.
I finally took #mjwillis suggestion and resolved this directly in SQL Server with the following:
DECLARE #sql nvarchar (255);
DECLARE #refTableName varchar(255) = 'Opportunities'
DECLARE #refColName varchar(255) = 'Id'
DECLARE #refValue uniqueidentifier = '2a8a0f61-fe5c-4dd7-8e6d-00c8340333c4'
Deleted User Key
DECLARE #refNewValue uniqueidentifier = '99999999-9999-9999-9999-999999999999'
DECLARE RelatedTableCursor CURSOR
LOCAL STATIC READ_ONLY FORWARD_ONLY
FOR
SELECT
result.TableName,
result.ColumnName
FROM
(
SELECT
OBJECT_NAME(f.parent_object_id) AS TableName,
COL_NAME(fc.parent_object_id,fc.parent_column_id) AS ColumnName,
SCHEMA_NAME(o.SCHEMA_ID) ReferenceSchemaName,
OBJECT_NAME (f.referenced_object_id) AS ReferenceTableName,
COL_NAME(fc.referenced_object_id,fc.referenced_column_id) AS ReferenceColumnName
FROM sys.foreign_keys AS f
INNER JOIN sys.foreign_key_columns AS fc ON f.OBJECT_ID = fc.constraint_object_id
INNER JOIN sys.objects AS o ON o.OBJECT_ID = fc.referenced_object_id
) result
WHERE
ReferenceTableName = #refTableName AND ReferenceColumnName = #refColName
OPEN RelatedTableCursor
WHILE 1 = 1
BEGIN
DECLARE #tableName varchar(255)
DECLARE #columnName varchar(255)
FETCH NEXT FROM RelatedTableCursor into #tableName, #columnName
IF ##fetch_status <> 0
BEGIN
BREAK
END
DECLARE #sql nvarchar (255);
SET #sql =
N'UPDATE [' + #tableName + '] ' +
'SET ' +
' [' + #columnName + '] = ''' + CONVERT(NVARCHAR(255), #refNewValue) + ''' ' +
'WHERE [' + #columnName + '] = ''' + CONVERT(NVARCHAR(255), #refValue) + ''' ';
-- Prevent some error (Duplicate record) that occurs when replace data in mapping table.
BEGIN TRY
-- exec sp_executesql #sql;
select #sql
END TRY
BEGIN CATCH
END CATCH
END
CLOSE RelatedTableCursor
DEALLOCATE RelatedTableCursor
SET #sql = 'DELETE FROM [' + #refTableName + '] WHERE ' + #refColName + ' = ''' + CONVERT(NVARCHAR(255), #refValue) + '''';
EXEC sp_executesql #sql;

SQL Server - Pass an Id from a table and check the colum values from all tables in database

I'm trying to write a stored procedure to search for a string in all tables of a SQL Server database. I was able to find a good stored procedure for this purpose
However I don't want to just put the #Tablenames manually, I want it to go to a table called Enums_Tables that has an ID, and use that ID as #Tablenames.
What I have being thinking to solve this:
I could write another stored procedure to select all Id's from Enums_Tables and execute the first stored procedure, like in here
I could also pass the parameter in C#, since I'm going to use it as a search textbox. But the ideal would be making a single stored procedure.
Could you please help me with this?
EDIT
Thanks to GPW I have been able to solve this problem. I also encountered problems with the collation, but I also solve it. Below is the final stored procedure.
USE [DynaForms]
GO
/****** Object: stored procedure [dbo].[SP_SearchTables] Script Date: 09/11/2017 14:59:15 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [dbo].[SP_SearchTables]
--#Tablenames VARCHAR(500)
#SearchStr NVARCHAR(60)
,#GenerateSQLOnly Bit = 0
,#SchemaNames VARCHAR(500) ='%'
AS
/*
Parameters and usage
#Tablenames -- Provide a single table name or multiple table name with comma seperated.
If left blank , it will check for all the tables in the database
Provide wild card tables names with comma seperated
EX :'%tbl%,Dim%' -- This will search the table having names comtains "tbl" and starts with "Dim"
#SearchStr -- Provide the search string. Use the '%' to coin the search. Also can provide multiple search with comma seperated
EX : X%--- will give data staring with X
%X--- will give data ending with X
%X%--- will give data containig X
%X%,Y%--- will give data containig X or starting with Y
%X%,%,,% -- Use a double comma to search comma in the data
#GenerateSQLOnly -- Provide 1 if you only want to generate the SQL statements without seraching the database.
By default it is 0 and it will search.
##SchemaNames -- Provide a single Schema name or multiple Schema name with comma seperated.
If left blank , it will check for all the tables in the database
Provide wild card Schema names with comma seperated
EX :'%dbo%,Sales%' -- This will search the Schema having names comtains "dbo" and starts with "Sales"
Samples :
1. To search data in a table
EXEC SP_SearchTables #Tablenames = 'T1'
,#SearchStr = '%TEST%'
The above sample searches in table T1 with string containing TEST.
2. To search in a multiple table
EXEC SP_SearchTables #Tablenames = 'T2'
,#SearchStr = '%TEST%'
The above sample searches in tables T1 & T2 with string containing TEST.
3. To search in a all table
EXEC SP_SearchTables #Tablenames = '%'
,#SearchStr = '%TEST%'
The above sample searches in all table with string containing TEST.
4. Generate the SQL for the Select statements
EXEC SP_SearchTables #Tablenames = 'T1'
,#SearchStr = '%TEST%'
,#GenerateSQLOnly = 1
5. To Search in tables with specfic name
EXEC SP_SearchTables #Tablenames = '%T1%'
,#SearchStr = '%TEST%'
,#GenerateSQLOnly = 0
6. To Search in multiple tables with specfic names
EXEC SP_SearchTables #Tablenames = '%T1%,Dim%'
,#SearchStr = '%TEST%'
,#GenerateSQLOnly = 0
7. To specify multiple search strings
EXEC SP_SearchTables #Tablenames = '%T1%,Dim%'
,#SearchStr = '%TEST%,TEST1%,%TEST2'
,#GenerateSQLOnly = 0
8. To search comma itself in the tables use double comma ",,"
EXEC SP_SearchTables #Tablenames = '%T1%,Dim%'
,#SearchStr = '%,,%'
,#GenerateSQLOnly = 0
EXEC SP_SearchTables #Tablenames = '%T1%,Dim%'
,#SearchStr = '%with,,comma%'
,#GenerateSQLOnly = 0
9. To Search by SchemaName
EXEC SP_SearchTables #Tablenames = '%T1%,Dim%'
,#SearchStr = '%,,%'
,#GenerateSQLOnly = 0
,#SchemaNames = '%dbo%,Sales%'
*/
SET NOCOUNT ON
DECLARE #MatchFound BIT
SELECT #MatchFound = 0
DECLARE #CheckTableNames Table
(
Schemaname sysname
,Tablename sysname
)
DECLARE #SearchStringTbl TABLE
(
SearchString VARCHAR(500)
)
DECLARE #SQLTbl TABLE
(
Tablename SYSNAME
,WHEREClause VARCHAR(MAX)
,SQLStatement VARCHAR(MAX)
,Execstatus BIT
)
DECLARE #SQL VARCHAR(MAX)
DECLARE #TableParamSQL VARCHAR(MAX)
DECLARE #SchemaParamSQL VARCHAR(MAX)
DECLARE #TblSQL VARCHAR(MAX)
DECLARE #tmpTblname sysname
DECLARE #ErrMsg VARCHAR(100)
/*
IF LTRIM(RTRIM(#Tablenames)) IN ('' ,'%')
BEGIN
INSERT INTO #CheckTableNames
SELECT Name
FROM sys.tables
END
ELSE
BEGIN
IF CHARINDEX(',',#Tablenames) > 0
SELECT #SQL = 'SELECT ''' + REPLACE(#Tablenames,',','''as TblName UNION SELECT ''') + ''''
ELSE
SELECT #SQL = 'SELECT ''' + #Tablenames + ''' as TblName '
SELECT #TblSQL = 'SELECT T.NAME
FROM SYS.TABLES T
JOIN (' + #SQL + ') tblsrc
ON T.name LIKE tblsrc.tblname '
INSERT INTO #CheckTableNames
EXEC(#TblSQL)
END
*/
--IF LTRIM(RTRIM(#Tablenames)) = ''
--BEGIN
-- SELECT #Tablenames = '%'
--END
IF LTRIM(RTRIM(#SchemaNames)) =''
BEGIN
SELECT #SchemaNames = '%'
END
--IF CHARINDEX(',',#Tablenames) > 0
-- SELECT #TableParamSQL = 'SELECT ''' + REPLACE(#Tablenames,',','''as TblName UNION SELECT ''') + ''''
--ELSE
-- SELECT #TableParamSQL = 'SELECT ''' + #Tablenames + ''' as TblName '
IF CHARINDEX(',',#SchemaNames) > 0
SELECT #SchemaParamSQL = 'SELECT ''' + REPLACE(#SchemaNames,',','''as SchemaName UNION SELECT ''') + ''''
ELSE
SELECT #SchemaParamSQL = 'SELECT ''' + #SchemaNames + ''' as SchemaName '
SELECT #TblSQL = 'SELECT SCh.NAME,T.NAME
FROM SYS.TABLES T
JOIN SYS.SCHEMAS SCh
ON SCh.SCHEMA_ID = T.SCHEMA_ID
INNER JOIN [DynaForms].[dbo].[Enums_Tables] et on
(et.Id = T.NAME COLLATE Latin1_General_CI_AS)'
INSERT INTO #CheckTableNames
(Schemaname,Tablename)
EXEC(#TblSQL)
IF NOT EXISTS(SELECT 1 FROM #CheckTableNames)
BEGIN
SELECT #ErrMsg = 'No tables are found in this database ' + DB_NAME() + ' for the specified filter'
PRINT #ErrMsg
RETURN
END
IF LTRIM(RTRIM(#SearchStr)) =''
BEGIN
SELECT #ErrMsg = 'Please specify the search string in #SearchStr Parameter'
PRINT #ErrMsg
RETURN
END
ELSE
BEGIN
SELECT #SearchStr = REPLACE(#SearchStr,',,,',',#DOUBLECOMMA#')
SELECT #SearchStr = REPLACE(#SearchStr,',,','#DOUBLECOMMA#')
SELECT #SearchStr = REPLACE(#SearchStr,'''','''''')
SELECT #SQL = 'SELECT ''' + REPLACE(#SearchStr,',','''as SearchString UNION SELECT ''') + ''''
INSERT INTO #SearchStringTbl
(SearchString)
EXEC(#SQL)
UPDATE #SearchStringTbl
SET SearchString = REPLACE(SearchString ,'#DOUBLECOMMA#',',')
END
INSERT INTO #SQLTbl
( Tablename,WHEREClause)
SELECT QUOTENAME(SCh.name) + '.' + QUOTENAME(ST.NAME),
(
SELECT '[' + SC.Name + ']' + ' LIKE ''' + REPLACE(SearchSTR.SearchString,'''','''''') + ''' OR ' + CHAR(10)
FROM SYS.columns SC
JOIN SYS.types STy
ON STy.system_type_id = SC.system_type_id
AND STy.user_type_id =SC.user_type_id
CROSS JOIN #SearchStringTbl SearchSTR
WHERE STY.name in ('varchar','char','nvarchar','nchar','text')
AND SC.object_id = ST.object_id
ORDER BY SC.name
FOR XML PATH('')
)
FROM SYS.tables ST
JOIN #CheckTableNames chktbls
ON chktbls.Tablename = ST.name
JOIN SYS.schemas SCh
ON ST.schema_id = SCh.schema_id
AND Sch.name = chktbls.Schemaname
WHERE ST.name <> 'SearchTMP'
GROUP BY ST.object_id, QUOTENAME(SCh.name) + '.' + QUOTENAME(ST.NAME) ;
UPDATE #SQLTbl
SET SQLStatement = 'SELECT * INTO SearchTMP FROM ' + Tablename + ' WHERE ' + substring(WHEREClause,1,len(WHEREClause)-5)
DELETE FROM #SQLTbl
WHERE WHEREClause IS NULL
WHILE EXISTS (SELECT 1 FROM #SQLTbl WHERE ISNULL(Execstatus ,0) = 0)
BEGIN
SELECT TOP 1 #tmpTblname = Tablename , #SQL = SQLStatement
FROM #SQLTbl
WHERE ISNULL(Execstatus ,0) = 0
IF #GenerateSQLOnly = 0
BEGIN
IF OBJECT_ID('SearchTMP','U') IS NOT NULL
DROP TABLE SearchTMP
EXEC (#SQL)
IF EXISTS(SELECT 1 FROM SearchTMP)
BEGIN
SELECT Tablename=#tmpTblname,* FROM SearchTMP
SELECT #MatchFound = 1
END
END
ELSE
BEGIN
PRINT REPLICATE('-',100)
PRINT #tmpTblname
PRINT REPLICATE('-',100)
PRINT replace(#SQL,'INTO SearchTMP','')
END
UPDATE #SQLTbl
SET Execstatus = 1
WHERE Tablename = #tmpTblname
END
IF #MatchFound = 0
BEGIN
SELECT #ErrMsg = 'No Matches are found in this database ' + DB_NAME() + ' for the specified filter'
PRINT #ErrMsg
RETURN
END
SET NOCOUNT OFF
Sorry in advance with the weird formatting, I can't put it more readable. I hope it helps someone. I also want to give credit to the onwer of the original stored procedure in here.
That stored procedure you linked to already has logic to check the table names in the database and populates a table variable with a list of tables to check. Just change this logic to Select from your ENUM_TABLES table instead. This could be based on an input parameter of #Id if you like...
In simple terms:
Remove the parameter #TableNames from the stored procedure
(optionally) replace the parameter with #ENUM_TABLE_ID or something
Change code in SP that looks like this:
IF LTRIM(RTRIM(#Tablenames)) = ''
/* Removed a load of lines looking at #TableNames...... */
....
SELECT #TblSQL = 'SELECT SCh.NAME,T.NAME
FROM SYS.TABLES T
JOIN SYS.SCHEMAS SCh
ON SCh.SCHEMA_ID = T.SCHEMA_ID
JOIN (' + #TableParamSQL + ') tblsrc
ON T.name LIKE tblsrc.tblname
JOIN (' + #SchemaParamSQL + ') schemasrc
ON SCh.name LIKE schemasrc.SchemaName
With something more like this:
SELECT #TblSQL = 'SELECT SCh.NAME,T.NAME
FROM SYS.TABLES T
JOIN SYS.SCHEMAS SCh
ON SCh.SCHEMA_ID = T.SCHEMA_ID
INNER JOIN ENUM_TABLES et on
(et.TABLENAME=T.NAME)
and (et.Id='+#ENUM_TABLE_ID+')'
And then I think it'll do what you want (lookup the list of tables from another table, based on an ID passed into the stored procedure)
(apologies for the slightly weird formatting of the SQL above; for some reason the SO markdown processor really didn't like that stuff, but it is hopefully readable. If anyone wants to try to edit this to improve it, be my guest.)

Retrieve all rows from all database tables with "Where" condition

I have a DB with 60 tables. In some of those tables I have a bit column named "Open" where I store a 0 if the record is not in use by an user (user access DB from a C# application) and an 1 if the record is in use.
Well, I need to get all the records from all the tables in my database where the "open" column value is true, or 1.
Is this even possible to do?
Here's a simple use of the undocumented sp_MSforeachtable:
EXEC sp_MSforeachtable
#command1='SELECT * FROM ? WHERE Open=1',
#whereand='AND o.id in (select object_id from sys.columns c where c.name=''Open'')'
Quick piece of code that gets list of tables within your database. Using a cursor loop through the answers checking it they have the fld named [open] and if it does the build a SQL statement and the execute this SQL string.
CREATE PROCEDURE usp_BulkTableOpenReport
AS
BEGIN
DECLARE #TBLS AS TABLE (REF INT IDENTITY (0,1), TABLENAME NVARCHAR(100), TABLEID BIGINT);
DECLARE #TBL AS NVARCHAR(100);
DECLARE #TBLID AS BIGINT;
DECLARE #SQL AS NVARCHAR(MAX);
DECLARE #I INT = 0;
DECLARE #M INT = 0;
DECLARE #V INT = 0
INSERT INTO #TBLS(TABLENAME,TABLEID)
SELECT NAME,OBJECT_ID FROM sys.tables
SELECT #M = MAX(REF) FROM #TBLS
WHILE #I <= #M
BEGIN
SELECT #TBL = TABLENAME, #TBLID= TABLEID FROM #TBLS WHERE REF = #I
/* CHECK TO MAKE INSURE THAT A FLD CALLED [OPEN] EXIST. */
SELECT #V = COUNT(*) FROM SYS.columns WHERE name = 'OPEN' AND OBJECT_ID = #TBLID
IF #V != 0
BEGIN
SET #SQL = 'SELECT * FROM [' + #TBL + '] WHERE [OPEN] = 1'
EXEC SP_EXECUTESQL #SQL
END;
SET #I = #I + 1
END;
END
GO
From your c# application exec the query "EXEC usp_BulkTableOpenReport" then loop through the table outputs.

Deleting all rows from all tables for a specific Database in a SQL Server [duplicate]

How to delete all rows from all tables in a SQL Server database?
Note that TRUNCATE won't work if you have any referential integrity set.
In that case, this will work:
EXEC sp_MSForEachTable 'DISABLE TRIGGER ALL ON ?'
GO
EXEC sp_MSForEachTable 'ALTER TABLE ? NOCHECK CONSTRAINT ALL'
GO
EXEC sp_MSForEachTable 'SET QUOTED_IDENTIFIER ON; DELETE FROM ?'
GO
EXEC sp_MSForEachTable 'ALTER TABLE ? WITH CHECK CHECK CONSTRAINT ALL'
GO
EXEC sp_MSForEachTable 'ENABLE TRIGGER ALL ON ?'
GO
Edit: To be clear, the ? in the statements is a ?. It's replaced with the table name by the sp_MSForEachTable procedure.
In my recent project my task was to clean an entire database by using sql statement and each table having many constraints like Primary Key and Foreign Key. There are more than 1000 tables in database so its not possible to write a delete query on each and ever table.
By using a stored procedure named sp_MSForEachTable which allows us to easily process some code against each and every table in a single database. It means that it is used to process a single T-SQL command or a different T-SQL commands against every table in the database.
So follow the below steps to truncate all tables in a SQL Server Database:
Step 1- Disable all constraints on the database by using below sql query :
EXEC sys.sp_msforeachtable 'ALTER TABLE ? NOCHECK CONSTRAINT ALL'
Step 2- Execute a Delete or truncate operation on each table of the database by using below sql command :
EXEC sys.sp_msforeachtable 'DELETE FROM ?'
Step 3- Enable all constraints on the database by using below sql statement:
EXEC sys.sp_MSForEachTable 'ALTER TABLE ? CHECK CONSTRAINT ALL'
I had to delete all the rows and did it with the next script:
DECLARE #Nombre NVARCHAR(MAX);
DECLARE curso CURSOR FAST_FORWARD
FOR
Select Object_name(object_id) AS Nombre from sys.objects where type = 'U'
OPEN curso
FETCH NEXT FROM curso INTO #Nombre
WHILE (##FETCH_STATUS <> -1)
BEGIN
IF (##FETCH_STATUS <> -2)
BEGIN
DECLARE #statement NVARCHAR(200);
SET #statement = 'DELETE FROM ' + #Nombre;
print #statement
execute sp_executesql #statement;
END
FETCH NEXT FROM curso INTO #Nombre
END
CLOSE curso
DEALLOCATE curso
Hope this helps!
In my case, I needed to set QUOTED_IDENTIFIER on. This led to a slight modification of Mark Rendle's answer above:
EXEC sp_MSforeachtable 'DISABLE TRIGGER ALL ON ?'
GO
EXEC sp_MSforeachtable 'ALTER TABLE ? NOCHECK CONSTRAINT ALL'
GO
EXEC sp_MSforeachtable 'SET QUOTED_IDENTIFIER ON; DELETE FROM ?'
GO
EXEC sp_MSforeachtable 'ALTER TABLE ? CHECK CONSTRAINT ALL'
GO
EXEC sp_MSforeachtable 'ENABLE TRIGGER ALL ON ?'
GO
Here is a solution that:
Drops constraints (thanks to this post)
Iterates through INFORMATION_SCHEMA.TABLES for a particular database
SELECTS tables based on some search criteria
Deletes all the data from those tables
Re-adds constraints
Allows for ignoring of certain tables such as sysdiagrams and __RefactorLog
I initially tried EXECUTE sp_MSforeachtable 'TRUNCATE TABLE ?', but that deleted my diagrams.
USE <DB name>;
GO
-- Disable all constraints in the database
EXEC sp_MSforeachtable "ALTER TABLE ? NOCHECK CONSTRAINT all"
declare #catalog nvarchar(250);
declare #schema nvarchar(250);
declare #tbl nvarchar(250);
DECLARE i CURSOR LOCAL FAST_FORWARD FOR select
TABLE_CATALOG,
TABLE_SCHEMA,
TABLE_NAME
from INFORMATION_SCHEMA.TABLES
where
TABLE_TYPE = 'BASE TABLE'
AND TABLE_NAME != 'sysdiagrams'
AND TABLE_NAME != '__RefactorLog'
OPEN i;
FETCH NEXT FROM i INTO #catalog, #schema, #tbl;
WHILE ##FETCH_STATUS = 0
BEGIN
DECLARE #sql NVARCHAR(MAX) = N'DELETE FROM [' + #catalog + '].[' + #schema + '].[' + #tbl + '];'
/* Make sure these are the commands you want to execute before executing */
PRINT 'Executing statement: ' + #sql
-- EXECUTE sp_executesql #sql
FETCH NEXT FROM i INTO #catalog, #schema, #tbl;
END
CLOSE i;
DEALLOCATE i;
-- Re-enable all constraints again
EXEC sp_MSforeachtable "ALTER TABLE ? WITH CHECK CHECK CONSTRAINT all"
Set nocount on
Exec sp_MSforeachtable 'Alter Table ? NoCheck Constraint All'
Exec sp_MSforeachtable
'
If ObjectProperty(Object_ID(''?''), ''TableHasForeignRef'')=1
Begin
-- Just to know what all table used delete syntax.
Print ''Delete from '' + ''?''
Delete From ?
End
Else
Begin
-- Just to know what all table used Truncate syntax.
Print ''Truncate Table '' + ''?''
Truncate Table ?
End
'
Exec sp_MSforeachtable 'Alter Table ? Check Constraint All'
If you just have constraints just paste this lines in the query and run it
EXEC sys.sp_msforeachtable 'ALTER TABLE ? NOCHECK CONSTRAINT ALL'
EXEC sys.sp_msforeachtable 'DELETE FROM ?'
EXEC sys.sp_MSForEachTable 'ALTER TABLE ? CHECK CONSTRAINT ALL'
You could delete all the rows from all tables using an approach like Rubens suggested, or you could just drop and recreate all the tables. Always a good idea to have the full db creation scripts anyway so that may be the easiest/quickest method.
This answer builds on Zach Smith's answer by resetting the identity column as well:
Disabling all constraints
Iterating through all tables except those you choose to exclude
Deletes all rows from the table
Resets the identity column if one exists
Re-enables all constraints
Here is the query:
-- Disable all constraints in the database
EXEC sp_msforeachtable "ALTER TABLE ? NOCHECK CONSTRAINT all"
declare #catalog nvarchar(250);
declare #schema nvarchar(250);
declare #tbl nvarchar(250);
DECLARE i CURSOR LOCAL FAST_FORWARD FOR select
TABLE_CATALOG,
TABLE_SCHEMA,
TABLE_NAME
from INFORMATION_SCHEMA.TABLES
where
TABLE_TYPE = 'BASE TABLE'
AND TABLE_NAME != 'sysdiagrams'
AND TABLE_NAME != '__RefactorLog'
-- Optional
-- AND (TABLE_SCHEMA = 'dbo')
OPEN i;
FETCH NEXT FROM i INTO #catalog, #schema, #tbl;
WHILE ##FETCH_STATUS = 0
BEGIN
DECLARE #sql NVARCHAR(MAX) = N'DELETE FROM [' + #catalog + '].[' + #schema + '].[' + #tbl + '];'
/* Make sure these are the commands you want to execute before executing */
PRINT 'Executing statement: ' + #sql
--EXECUTE sp_executesql #sql
-- Reset identity counter if one exists
IF ((SELECT OBJECTPROPERTY( OBJECT_ID(#catalog + '.' + #schema + '.' + #tbl), 'TableHasIdentity')) = 1)
BEGIN
SET #sql = N'DBCC CHECKIDENT ([' + #catalog + '.' + #schema + '.' + #tbl + '], RESEED, 0)'
PRINT 'Executing statement: ' + #sql
--EXECUTE sp_executesql #sql
END
FETCH NEXT FROM i INTO #catalog, #schema, #tbl;
END
CLOSE i;
DEALLOCATE i;
-- Re-enable all constraints again
EXEC sp_msforeachtable "ALTER TABLE ? WITH CHECK CHECK CONSTRAINT all"
For some requirements we might have to skip certain tables. I wrote the below script to add some extra conditions to filter the list of tables. The below script will also display the pre delete count and post delete count.
IF OBJECT_ID('TEMPDB..#TEMPRECORDCOUNT') IS NOT NULL
DROP TABLE #TEMPRECORDCOUNT
CREATE TABLE #TEMPRECORDCOUNT
( TABLENAME NVARCHAR(128)
,PREDELETECOUNT BIGINT
,POSTDELETECOUNT BIGINT
)
INSERT INTO #TEMPRECORDCOUNT (TABLENAME, PREDELETECOUNT, POSTDELETECOUNT)
SELECT O.name TableName
,DDPS.ROW_COUNT PREDELETECOUNT
,NULL FROM sys.objects O
INNER JOIN (
SELECT OBJECT_ID, SUM(row_count) ROW_COUNT
FROM SYS.DM_DB_PARTITION_STATS
GROUP BY OBJECT_ID
) DDPS ON DDPS.OBJECT_ID = O.OBJECT_ID
WHERE O.type = 'U' AND O.name NOT LIKE 'OC%' AND O.schema_id = 1
DECLARE #TableName NVARCHAR(MAX);
DECLARE TableDeleteCursor CURSOR FAST_FORWARD
FOR
SELECT TableName from #TEMPRECORDCOUNT
OPEN TableDeleteCursor
FETCH NEXT FROM TableDeleteCursor INTO #TableName
WHILE (##FETCH_STATUS <> -1)
BEGIN
IF (##FETCH_STATUS <> -2)
BEGIN
DECLARE #STATEMENT NVARCHAR(MAX);
SET #STATEMENT = ' DISABLE TRIGGER ALL ON ' + #TableName +
'; ALTER TABLE ' + #TableName + ' NOCHECK CONSTRAINT ALL' +
'; DELETE FROM ' + #TableName +
'; ALTER TABLE ' + #TableName + ' CHECK CONSTRAINT ALL' +
'; ENABLE TRIGGER ALL ON ' + #TableName;
PRINT #STATEMENT
EXECUTE SP_EXECUTESQL #STATEMENT;
END
FETCH NEXT FROM TableDeleteCursor INTO #TableName
END
CLOSE TableDeleteCursor
DEALLOCATE TableDeleteCursor
UPDATE T
SET T.POSTDELETECOUNT = I.ROW_COUNT
FROM #TEMPRECORDCOUNT T
INNER JOIN (
SELECT O.name TableName, DDPS.ROW_COUNT ROW_COUNT
FROM sys.objects O
INNER JOIN (
SELECT OBJECT_ID, SUM(row_count) ROW_COUNT
FROM SYS.DM_DB_PARTITION_STATS
GROUP BY OBJECT_ID
) DDPS ON DDPS.OBJECT_ID = O.OBJECT_ID
WHERE O.type = 'U' AND O.name NOT LIKE 'OC%' AND O.schema_id = 1
) I ON I.TableName COLLATE DATABASE_DEFAULT = T.TABLENAME
SELECT * FROM #TEMPRECORDCOUNT
ORDER BY TABLENAME ASC
--Load tables to delete from
SELECT
DISTINCT
' Delete top 1000000 from <DBName>.<schema>.' + c.TABLE_NAME + ' WHERE <Filter Clause Here>' AS query,c.TABLE_NAME AS TableName, IsDeleted=0, '<InsertSomeDescriptorHere>' AS [Source]--,t.TABLE_TYPE, c.*
INTO dbo.AllTablesToDeleteFrom
FROM INFORMATION_SCHEMA.TABLES AS t
INNER JOIN information_schema.columns c ON c.TABLE_NAME = t.TABLE_NAME
WHERE c.COLUMN_NAME = '<column name>'
AND c.TABLE_SCHEMA = 'dbo'
AND c.TABLE_CATALOG = '<DB Name here>'
AND t.TABLE_TYPE='Base table'
--AND t.TABLE_NAME LIKE '<put filter here>'
DECLARE #TableSelect NVARCHAR(1000)= '';
DECLARE #Table NVARCHAR(1000)= '';
DECLARE #IsDeleted INT= 0;
DECLARE #NumRows INT = 1000000;
DECLARE #Source NVARCHAR(50)='';
WHILE ( #IsDeleted = 0 )
BEGIN
--This grabs one table at a time to be deleted from. #TableSelect has the sql to execute. it is important to order by IsDeleted ASC
--because it will pull tables to delete from by those that have a 0=IsDeleted first. Once the loop grabs a table with IsDeleted=1 then this will pop out of loop
SELECT TOP 1
#TableSelect = query,
#IsDeleted = IsDeleted,
#Table = TableName,
#Source=[a].[Source]
FROM dbo.AllTablesToDeleteFrom a
WHERE a.[Source]='SomeDescriptorHere'--use only if needed
ORDER BY a.IsDeleted ASC;--this is required because only those records returned with IsDeleted=0 will run through loop
--SELECT #Table; can add this in to monitor what table is being deleted from
WHILE ( #NumRows = 1000000 )--only delete a million rows at a time?
BEGIN
EXEC sp_executesql #TableSelect;
SET #NumRows = ##ROWCOUNT;
--IF #NumRows = 1000000 --can do something here if needed
--One wants this loop to continue as long as a million rows is deleted. Once < 1 million rows is deleted it pops out of loop
--and grabs next table to delete
-- BEGIN
--SELECT #NumRows;--can add this in to see current number of deleted records for table
INSERT INTO dbo.DeleteFromAllTables
( tableName,
query,
cnt,
[Source]
)
SELECT #Table,
#TableSelect,
#NumRows,
#Source;
-- END;
END;
SET #NumRows = 1000000;
UPDATE a
SET a.IsDeleted = 1
FROM dbo.AllTablesToDeleteFrom a
WHERE a.TableName = #Table;
--flag this as deleted so you can move on to the next table to delete from
END;
if you want to delete the whole table, you must follow the next SQL instruction
Delete FROM TABLE Where PRIMARY_KEY_ is Not NULL;

Categories