I would like this to be the ultimate discussion on how to check if a table exists in SQL Server 2000/2005 using SQL Statements.
Here are two possible ways of doing it. Which one is the standard/best way of doing it?
First way:
IF EXISTS (SELECT 1
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_TYPE='BASE TABLE'
AND TABLE_NAME='mytablename')
SELECT 1 AS res ELSE SELECT 0 AS res;
Second way:
IF OBJECT_ID (N'mytablename', N'U') IS NOT NULL
SELECT 1 AS res ELSE SELECT 0 AS res;
MySQL provides the simple
SHOW TABLES LIKE '%tablename%';
statement. I am looking for something similar.
For queries like this it is always best to use an INFORMATION_SCHEMA view. These views are (mostly) standard across many different databases and rarely change from version to version.
To check if a table exists use:
IF (EXISTS (SELECT *
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_SCHEMA = 'TheSchema'
AND TABLE_NAME = 'TheTable'))
BEGIN
--Do Stuff
END
Also note that if for any reason you need to check for a temporary table you can do this:
if OBJECT_ID('tempdb..#test') is not null
--- temp table exists
We always use the OBJECT_ID style for as long as I remember
IF OBJECT_ID('*objectName*', 'U') IS NOT NULL
Please see the below approaches,
Approach 1: Using INFORMATION_SCHEMA.TABLES view
We can write a query like below to check if a Customers Table exists in the current database.
IF EXISTS (SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = N'Customers')
BEGIN
PRINT 'Table Exists'
END
Approach 2: Using OBJECT_ID() function
We can use OBJECT_ID() function like below to check if a Customers Table exists in the current database.
IF OBJECT_ID(N'dbo.Customers', N'U') IS NOT NULL
BEGIN
PRINT 'Table Exists'
END
Approach 3: Using sys.Objects Catalog View
We can use the Sys.Objects catalog view to check the existence of the Table as shown below:
IF EXISTS(SELECT 1 FROM sys.Objects WHERE Object_id = OBJECT_ID(N'dbo.Customers') AND Type = N'U')
BEGIN
PRINT 'Table Exists'
END
Approach 4: Using sys.Tables Catalog View
We can use the Sys.Tables catalog view to check the existence of the Table as shown below:
IF EXISTS(SELECT 1 FROM sys.Tables WHERE Name = N'Customers' AND Type = N'U')
BEGIN
PRINT 'Table Exists'
END
Approach 5: Avoid Using sys.sysobjects System table
We should avoid using sys.sysobjects System Table directly, direct access to it will be deprecated in some future versions of the Sql Server. As per Microsoft BOL link, Microsoft is suggesting to use the catalog views sys.objects/sys.tables instead of sys.sysobjects system table directly.
IF EXISTS(SELECT name FROM sys.sysobjects WHERE Name = N'Customers' AND xtype = N'U')
BEGIN
PRINT 'Table Exists'
END
referred from: http://sqlhints.com/2014/04/13/how-to-check-if-a-table-exists-in-sql-server/
Looking for a table on a different database:
if exists (select * from MyOtherDatabase.sys.tables where name = 'MyTable')
print 'Exists'
Just wanted to mention one situation where it would probably be a little easier to use the OBJECT_ID method. The INFORMATION_SCHEMA views are objects under each database-
The information schema views are defined in a special schema named
INFORMATION_SCHEMA. This schema is contained in each database.
https://msdn.microsoft.com/en-us/library/ms186778.aspx
Therefore all tables you access using
IF EXISTS (SELECT 1
FROM [database].INFORMATION_SCHEMA.TABLES
WHERE TABLE_TYPE='BASE TABLE'
AND TABLE_NAME='mytablename')
SELECT 1 AS res ELSE SELECT 0 AS res;
will only reflect what is in [database]. If you wanted to check if tables in another database exist, without dynamically changing the [database] each time, OBJECT_ID will let you do this out of the box. Ex-
IF OBJECT_ID (N'db1.schema.table1', N'U') IS NOT NULL
SELECT 1 AS res ELSE SELECT 0 AS res;
works just as well as
IF OBJECT_ID (N'db2.schema.table1', N'U') IS NOT NULL
SELECT 1 AS res ELSE SELECT 0 AS res;
SQL SERVER 2016 Edit:
Starting with 2016, Microsoft simplified the ability to check for non-existent objects prior to dropping, by adding the if exists keywords to drop statements. For example,
drop table if exists mytablename
will do the same thing as OBJECT_ID / INFORMATION_SCHEMA wrappers, in 1 line of code.
https://blogs.msdn.microsoft.com/sqlserverstorageengine/2015/11/03/drop-if-exists-new-thing-in-sql-server-2016/
IF OBJECT_ID('mytablename') IS NOT NULL
Using the Information Schema is the SQL Standard way to do it, so it should be used by all databases that support it. See Approach 1 in this answer.
You can use below code
IF (OBJECT_ID('TableName') IS NOT NULL )
BEGIN
PRINT 'Table Exists'
END
ELSE
BEGIN
PRINT 'Table NOT Exists'
END
Or
IF (EXISTS (SELECT * FROM sys.tables WHERE [name] = 'TableName'))
BEGIN
PRINT 'Table Exists'
END
ELSE
BEGIN
PRINT 'Table NOT Exists'
END
IF EXISTS
(
SELECT *
FROM sys.objects
WHERE object_id = OBJECT_ID(N'[dbo].[Mapping_APCToFANavigator]')
AND
type in (N'U')
)
BEGIN
-- Do whatever you need to here.
END
Here in the above code, the table name is Mapping_APCToFANavigator.
If you need to work on different databases:
DECLARE #Catalog VARCHAR(255)
SET #Catalog = 'MyDatabase'
DECLARE #Schema VARCHAR(255)
SET #Schema = 'dbo'
DECLARE #Table VARCHAR(255)
SET #Table = 'MyTable'
IF (EXISTS (SELECT * FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_CATALOG = #Catalog
AND TABLE_SCHEMA = #Schema
AND TABLE_NAME = #Table))
BEGIN
--do stuff
END
I know it is an old question but I have found this possibility if you plan to call it often.
create procedure Table_Exists
#tbl varchar(50)
as
return (select count(*) from sysobjects where type = 'U' and name = #tbl)
go
Just adding here, for the benefit of developers and fellow DBAs
a script that receives #Tablename as a parameter
(which may or may not contain the schemaname) and returns the info below if the schema.table exists:
the_name object_id the_schema the_table the_type
[Facts].[FactBackOrder] 758293761 Facts FactBackOrder Table
I produced this script to be used inside other scripts every time I need to test whether or not a table or view exists, and when it does, get its object_id to be used for other purposes.
It raises an error when either you passed an empty string, wrong schema name or wrong table name.
this could be inside a procedure and return -1 for example.
As an example, I have a table called "Facts.FactBackOrder" in one of my Data Warehouse databases.
This is how I achieved this:
PRINT 'THE SERVER IS ' + ##SERVERNAME
--select db_name()
PRINT 'THE DATABASE IS ' + db_NAME()
PRINT ''
GO
SET NOCOUNT ON
GO
--===================================================================================
-- #TableName is the parameter
-- the object we want to deal with (it might be an indexed view or a table)
-- the schema might or might not be specified
-- when not specified it is DBO
--===================================================================================
DECLARE #TableName SYSNAME
SELECT #TableName = 'Facts.FactBackOrder'
--===================================================================================
--===================================================================================
DECLARE #Schema SYSNAME
DECLARE #I INT
DECLARE #Z INT
SELECT #TableName = LTRIM(RTRIM(#TableName))
SELECT #Z = LEN(#TableName)
IF (#Z = 0) BEGIN
RAISERROR('Invalid #Tablename passed.',16,1)
END
SELECT #I = CHARINDEX('.',#TableName )
--SELECT #TableName ,#I
IF #I > 0 BEGIN
--===================================================================================
-- a schema and table name have been passed
-- example Facts.FactBackOrder
-- #Schema = Fact
-- #TableName = FactBackOrder
--===================================================================================
SELECT #Schema = SUBSTRING(#TABLENAME,1,#I-1)
SELECT #TableName = SUBSTRING(#TABLENAME,#I+1,#Z-#I)
END
ELSE BEGIN
--===================================================================================
-- just a table name have been passed
-- so the schema will be dbo
-- example Orders
-- #Schema = dbo
-- #TableName = Orders
--===================================================================================
SELECT #Schema = 'DBO'
END
--===================================================================================
-- Check whether the #SchemaName is valid in the current database
--===================================================================================
IF NOT EXISTS ( SELECT * FROM INFORMATION_SCHEMA.SCHEMATA K WHERE K.[SCHEMA_NAME] = #Schema ) BEGIN
RAISERROR('Invalid Schema Name.',16,1)
END
--SELECT #Schema as [#Schema]
-- ,#TableName as [#TableName]
DECLARE #R1 TABLE (
THE_NAME SYSNAME
,THE_SCHEMA SYSNAME
,THE_TABLE SYSNAME
,OBJECT_ID INT
,THE_TYPE SYSNAME
,PRIMARY KEY CLUSTERED (THE_SCHEMA,THE_NAME)
)
;WITH RADHE_01 AS (
SELECT QUOTENAME(SCHEMA_NAME(O.schema_id)) + '.' + QUOTENAME(O.NAME) AS [the_name]
,the_schema=SCHEMA_NAME(O.schema_id)
,the_table=O.NAME
,object_id =o.object_id
,[the_type]= CASE WHEN O.TYPE = 'U' THEN 'Table' ELSE 'View' END
from sys.objects O
where O.is_ms_shipped = 0
AND O.TYPE IN ('U','V')
)
INSERT INTO #R1 (
THE_NAME
,THE_SCHEMA
,THE_TABLE
,OBJECT_ID
,THE_TYPE
)
SELECT the_name
,the_schema
,the_table
,object_id
,the_type
FROM RADHE_01
WHERE the_schema = #Schema
AND the_table = #TableName
IF (##ROWCOUNT = 0) BEGIN
RAISERROR('Invalid Table Name.',16,1)
END
ELSE BEGIN
SELECT THE_NAME
,THE_SCHEMA
,THE_TABLE
,OBJECT_ID
,THE_TYPE
FROM #R1
END
In SQL Server 2000 you can try:
IF EXISTS(SELECT 1 FROM sysobjects WHERE type = 'U' and name = 'MYTABLENAME')
BEGIN
SELECT 1 AS 'res'
END
IF EXISTS
(
SELECT *
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_SCHEMA = 'PutSchemaHere'
AND
TABLE_NAME = 'PutTableNameHere'
)
Something important to know for anybody who hasn't found their solution yet:
SQL server != MYSQL.
If you want to do it with MYSQL, it is quite simple
$sql = "SELECT 1 FROM `db_name`.`table_name` LIMIT 1;";
$result = mysql_query($sql);
if( $result == false )
echo "table DOES NOT EXIST";
else
echo "table exists";
Posting this here because it's the top hit at Google.
I've had some problems either with selecting from INFORMATIONAL_SCHEME and OBJECT_ID. I don't know if it's an issue of ODBC driver or something.. Queries from SQL management studio, both, were okay.
Here is the solution:
SELECT COUNT(*) FROM <yourTableNameHere>
So, if the query fails, there is, probably, no such table in the database (or you don't have access permissions to it).
The check is done by comparing the value (integer in my case) returned by SQL executor which deals with ODBC driver..
if (sqlexec(conectionHandle, 'SELECT COUNT(*) FROM myTable') == -1) {
// myTable doesn't exist..
}
IF EXISTS (
SELECT *
FROM INFORMATION_SCHEMA.TABLES
WHERE
TABLE_CATALOG = 'Database Name' and
TABLE_NAME = 'Table Name' and
TABLE_SCHEMA = 'Schema Name') -- Database and Schema name in where statement can be deleted
BEGIN
--TABLE EXISTS
END
ELSE BEGIN
--TABLE DOES NOT EXISTS
END
You can use this :
IF OBJECT_ID (N'dbo.T', N'U') IS NOT NULL
BEGIN
print 'deleted table';
drop table t
END
else
begin
print 'table not found'
end
Create table t (id int identity(1,1) not null, name varchar(30) not null, lastname varchar(25) null)
insert into t( name, lastname) values('john','doe');
insert into t( name, lastname) values('rose',NULL);
Select * from t
1 john doe
2 rose NULL
-- clean
drop table t
I think the following query works:
IF EXISTS (select * from sys.tables
WHERE name='mytablename' )
BEGIN
print 'table exists in the database'
END
IF EXISTS ( SELECT * FROM dbo.sysobjects WHERE id = OBJECT_ID(N'dbo.TableName') AND OBJECTPROPERTY(id, N'IsUserTable') = 1 )
BEGIN
SELECT * FROM dbo.TableName;
END
GO
There is one more option to check if the table exists across databases
IF EXISTS(SELECT 1 FROM [change-to-your-database].SYS.TABLES WHERE NAME = 'change-to-your-table-name')
BEGIN
-- do whatever you want
END
If anyone is trying to do this same thing in linq to sql (or especially linqpad) turn on option to include system tables and views and do this code:
let oSchema = sys.Schemas.FirstOrDefault(s=>s.Name==a.schema )
where oSchema !=null
let o=oSchema!=null?sys.Objects.FirstOrDefault (o => o.Name==a.item && o.Schema_id==oSchema.Schema_id):null
where o!=null
given that you have an object with the name in a property called item, and the schema in a property called schema where the source variable name is a
select name from SysObjects where xType='U' and name like '%xxx%' order by name
If this is to be the 'ultimate' discussion, then it should be noted that Larry Leonard's script can query a remote server as well if the servers are linked.
if exists (select * from REMOTE_SERVER.MyOtherDatabase.sys.tables where name = 'MyTable')
print 'Exists'
-- -- create procedure to check if a table exists
DELIMITER $$
DROP PROCEDURE IF EXISTS `checkIfTableExists`;
CREATE PROCEDURE checkIfTableExists(
IN databaseName CHAR(255),
IN tableName CHAR(255),
OUT boolExistsOrNot CHAR(40)
)
BEGIN
SELECT count(*) INTO boolExistsOrNot FROM information_schema.TABLES
WHERE (TABLE_SCHEMA = databaseName)
AND (TABLE_NAME = tableName);
END $$
DELIMITER ;
-- -- how to use : check if table migrations exists
CALL checkIfTableExists('muDbName', 'migrations', #output);
i taking here creating a view as example.
Because ALTER/CREATE commands can't be within BEGIN/END blocks. You need to test for existence and the drop it before doing a create
IF Object_ID('TestView') IS NOT NULL
DROP VIEW TestView
GO
CREATE VIEW TestView
as
. . .
GO
If you are woried about the permissions being lost you can script the GRANT statements as well and re-run those at the end.
You could wrap the create/alter into a string and do an EXEC - that might get ugly for large views
DECLARE #SQL as varchar(4000)
-- set to body of view
SET #SQL = 'SELECT X, Y, Z FROM TABLE'
IF Object_ID('TestView') IS NULL
SET #SQL = 'CREATE VIEW TestView AS ' + #SQL
ELSE
SET #SQL = 'ALTER VIEW TestView AS ' + #SQL
Run this query to check if the table exists in the database:
IF(SELECT TABLE_NAME from INFORMATION_SCHEMA.TABLES where TABLE_NAME = 'YourTableName') IS NOT NULL
PRINT 'Table Exists';
consider in one database you have a table t1. you want to run script on other Database like - if t1 exist then do nothing else create t1.
To do this open visual studio and do the following:
Right click on t1, then Script table as, then DROP and Create To, then New Query Editor
you will find your desired query. But before executing that script don't forget to comment out the drop statement in the query as you don't want to create new one if there is already one.
Thanks
Related
I have basic procedure which basically looks like following:
create procedure zsp_selectallupceans_list
(#UPCList nvarchar(4000),
#EANList nvarchar(4000))
as
select *
from data as dd
where dd.UPC in (--myUPC list) or dd.EAN in (--myEAN list)
This is the basic idea. Now I need to somehow split this string that I passed from my C# application and it would look like following for the UPC and EAN List:
where dd.UPC in ('123','456','567') or dd.EAN in('1234','5542','412')
The UPCList parameter that is passed from C# application looks like:
'123,456,567' and eanlist: '1234,5542,412'
I have found a method which looks like this:
CREATE FUNCTION dbo.splitstring
(#stringToSplit VARCHAR(MAX))
RETURNS
#returnList TABLE ([Name] [NVARCHAR](500))
AS
BEGIN
DECLARE #name NVARCHAR(255)
DECLARE #pos INT
WHILE CHARINDEX(',', #stringToSplit) > 0
BEGIN
SELECT #pos = CHARINDEX(',', #stringToSplit)
SELECT #name = SUBSTRING(#stringToSplit, 1, #pos-1)
INSERT INTO #returnList
SELECT #name
SELECT #stringToSplit = SUBSTRING(#stringToSplit, #pos+1, LEN(#stringToSplit)-#pos)
END
INSERT INTO #returnList
SELECT #stringToSplit
RETURN
END
And the usage of this function is like following:
SELECT * FROM dbo.splitstring('91,12,65,78,56,789')
where the output is these numbers where they are split and output as a result.
Now I just need to somehow combine all this so that I can form a proper where statement based on passed parameter UPCList and EANList
Can someone help me out with this?
Updating your stored proc as below should do the trick:
create procedure zsp_selectallupceans_list
(
#UPCList nvarchar(4000),
#EANList nvarchar(4000)
)
as
select *
from data as dd
where dd.UPC in (SELECT * FROM dbo.SplitString(#UPCList)) OR
dd.EAN in (SELECT * FROM dbo.SplitString(#EANList))
You pretty much have the answer:
Compile and save the splitstring function and then your where clause will look like the following:
where dd.UPC in (Select Name From splitstring(--myUpcList)) or dd.EAN in (Select Name from splitstring(--myEanList)
Here is an XML based function for string splitting, this method is much faster than the SUBSTRING method you already found. It is also recommended to use EXISTS instead of IN for performance improvement also, see here for more information on this.
CREATE FUNCTION [dbo].[SplitString]
(
#string nvarchar(max),
#delimiter nvarchar(5)
) RETURNS #t TABLE
(
val nvarchar(500)
)
AS
BEGIN
declare #xml xml
set #xml = N'<root><r>' + replace(#string,#delimiter,'</r><r>') + '</r></root>'
insert into #t(val)
select
r.value('.','varchar(500)') as item
from #xml.nodes('//root/r') as records(r)
RETURN
END
To use:
SELECT *
FROM data t
WHERE EXISTS (SELECT 1 FROM dbo.SplitString(#UPCList,',') S1 WHERE t.UPC=S1.val)
OR EXISTS (SELECT 1 FROM dbo.SplitString(#EANList,',') S2 WHERE t.EAN=S2.val)
I have got this query which is entered by user at run time.
SELECT * FROM Reports
WHERE ReportDate > DATEADD(d, #Days, getdate())
AND ReportCode = cast(#Reportcode as int)
Is there any way in C# .Net or SQL to retrieve the parameter names #Days and #ReportCode from this sql query?
Regex or string matching using # character is not full proof as parameter names may or may not end with a space. They can be immediately followed by a comma or parenthesis etc. and the name itself can contain a special character.
If I execute this query without providing parameter values, the sql engine throws exception Must declare the scalar variable "#Days". I can catch the exception and get first parameter name, but then it would be very complex to get next parameter in query.
exec sp_describe_undeclared_parameters N'SELECT * FROM Reports
WHERE ReportDate > DATEADD(d, #Days, getdate())
AND ReportCode = cast(#Reportcode as int)'
outputs:
parameter_ordinal name suggested_system_type_id suggested_system_type_name
----------------- ------------- ------------------------ ----------------------------
1 #Days 56 int
2 #Reportcode 56 int
(lots more columns skipped)
However, this is a SQL Server feature, not an ADO.NET one.
If I execute this query without providing parameter values,
The key trick here is remarkably simple: supply the correct parameters
Note: you can also use #params to tell it about the ones you already know about. For more details, see the documentation.
create table login_db(UserName varchar(50),Password varchar(50))
go
create proc sp_logininsertdb
(#UserName varchar(50),#Password varchar(50))
as
begin
insert into login_db values(#UserName,#Password)
end
drop proc sp_logininsertdb
exec sp_logininsertdb #UserName='admin',#Password='admin'
go
create proc sp_loginviewdb
as
select *from login_db
exec sp_loginview_db
create table addemployee_db(id int identity(1,1),employeename varchar(50),dob Date,location varchar(50),gender varchar(50),doj Date,experience int,ctc int,designation varchar(50),unithead varchar(50),projectid int)
go
create procedure sp_addemployeedb(#id int out,#employeename varchar(50),#dob Date,#location varchar(50),#gender varchar(50),#doj Date,#experience int,#ctc int,#designation varchar(50),#unithead varchar(50),#projectid int)
as
begin
insert into addemployee_db values (#employeename,#dob,#location,#gender,#doj,#experience,#ctc,#designation,#unithead,#projectid)
set #id=##IDENTITY
end
declare #result int
exec sp_addemployee #id=#result output,#employeename='lokesh',
#dob='03/16/1994',#location='tvm',#gender='male',#doj='01/18/2016',
#experience=1,#ctc=4,#designation='ASE',#unithead='head1',#projectid='001'
print #result
go
create proc sp_viewemployee_db
as
begin
select * from addemployee_db
end
exec sp_viewemployee_db
drop proc sp_updateemployee_db
drop proc sp_editemployee_db
go
create procedure sp_editemployee_db(#id int,#employeename varchar(50),#dob Date,#location varchar(50),#gender varchar(50),#doj Date,#experience int,#ctc int,#designation varchar(50),#unithead varchar(50),#projectid int)
as
begin
update addemployee_db set employeename=#employeename,dob=#dob,location=#location,gender=#gender,doj=#doj,experience=#experience,ctc=#ctc,designation=#designation,unithead=#unithead,projectid=#projectid
where id=#id
end
exec sp_editemployee_db #id=10,#employeename='avaneesh',
#dob='10/11/1992',#location='Trivandrum',#gender='male',#doj='01/18/2016',
#experience=2,#ctc=7,#designation='ASET',#unithead='head2',#projectid='002'
go
create proc sp_updateemployee_db
as
begin
select * from addemployee_db
exec sp_updateemployee_db
end
drop proc sp_deletemployee_db
go
create proc sp_deletemployee_db
(#id int out)
as
begin
delete from addemployee_db where id=#id
end
exec sp_deletemployee #id=12
go
create proc sp_deleteemployee_db
as
begin
select * from addemployee_db
exec sp_deleteemployee_db
end
exec sp1_login_db
create table databinding_db(location varchar(20))
go
create proc sp_databindinginsertdb
(
#location varchar(20)
)
as
begin
insert into databinding_db
values(#location)
end
drop table databinding_db
drop proc sp_databindinginsertdb
select * from databinding_db
exec sp_databindinginsertdb 'chennai'
exec sp_databindinginsertdb 'trivandrum'
exec sp_databindinginsertdb 'puducherry'
exec sp_databindinginsertdb 'trichy'
select * from databinding_db
go
create proc sp_databindingdb
as
begin
select * from databinding_db
end
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.
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;
I am working on a web application where there are many tables but two will suffice to illustrate my problem:
User
Order
Let us say that the User table has a primary key "UserID", which is a foreign key in the Order table called "CreatedBy_UserID".
Before deleting a User, I would like to check if the Order table has a record created by the soon-to-be deleted user.
I know that a SqlException occurs if I try to delete the user but let us say that I want to check beforehand that the Order table does not have any records created by this user? Is there any SQL code which I could run which will check all foreign keys of a table if that row is being referenced?
This for me is generally useful code as I could remove the option for deletion altogether if it can be detected that the user exists in these other tables.
I don't want a simple query (SELECT COUNT(*) FROM Order WHERE CreatedBy_UserID == #userID) because this will not work if I create another foreign key to the Order table. Instead I want something that will traverse all foreign keys.
Can this be done?
Below is code for an sp that I've used in the past to perform this task (please excuse the indenting):
create proc dbo.usp_ForeignKeyCheck(
#tableName varchar(100),
#columnName varchar(100),
#idValue int
) as begin
set nocount on
declare fksCursor cursor fast_forward for
select tc.table_name, ccu.column_name
from
information_schema.table_constraints tc join
information_schema.constraint_column_usage ccu on tc.constraint_name = ccu.constraint_name join
information_schema.referential_constraints rc on tc.constraint_name = rc.constraint_name join
information_schema.table_constraints tc2 on rc.unique_constraint_name = tc2.constraint_name join
information_schema.constraint_column_usage ccu2 on tc2.constraint_name = ccu2.constraint_name
where tc.constraint_type = 'Foreign Key' and tc2.table_name = #tableName and ccu2.column_name = #columnName
order by tc.table_name
declare
#fkTableName varchar(100),
#fkColumnName varchar(100),
#fkFound bit,
#params nvarchar(100),
#sql nvarchar(500)
open fksCursor
fetch next from fksCursor
into #fkTableName, #fkColumnName
set #fkFound = 0
set #params=N'#fkFound bit output'
while ##fetch_status = 0 and coalesce(#fkFound,0) <> 1 begin
select #sql = 'set #fkFound = (select top 1 1 from [' + #fkTableName + '] where [' + #fkColumnName + '] = ' + cast(#idValue as varchar(10)) + ')'
print #sql
exec sp_executesql #sql,#params,#fkFound output
fetch next from fksCursor
into #fkTableName, #fkColumnName
end
close fksCursor
deallocate fksCursor
select coalesce(#fkFound,0)
return 0
end
This will select a value of 1 if a row has any foreign key references.
The call you would need would be:
exec usp_ForeignKeyCheck('User','UserID',23)
There is no clean way to iterate through all FK columns where multiple exist. You'd have to build some dynamic SQL to query the system tables and test each in turn.
Personally, I wouldn't do this. I know what FKs I have: I'll test each in turn
...
IF EXISTS (SELECT * FROM Order WHERE CreatedBy_UserID == #userID)
RAISERROR ('User created Orders ', 16, 1)
IF EXISTS (SELECT * FROM Order WHERE PackedBy_UserID == #userID)
RAISERROR ('User packed Orders', 16, 1)
...
You wouldn't dynamically iterate through each property of some user object and generically test each one would you? You'd have code for each property
This code will give you a list of the foreign keys which are defined for a specifit table:
select distinct name from sys.objects
where object_id in ( select constraint_object_id from sys.foreign_key_columns as fk
where fk.Parent_object_id = (select object_id from sys.tables
where name = 'tablename') )
You can use transaction to check it.
I know it seems like stone ax, but it working fast and stable.
private bool TestUser(string connectionString, int userID)
{
var result = true;
using (SqlConnection connection = new SqlConnection(connectionString))
{
connection.Open();
var command = connection.CreateCommand();
var transaction = connection.BeginTransaction();
command.Connection = connection;
command.Transaction = transaction;
try
{
command.CommandText = "DELETE User WHERE UserID = " + userID.ToString();
command.ExecuteNonQuery();
transaction.Rollback();
}
catch
{
result = false;
}
}
return result;
}