T-SQL Check if table exists in schema - sql-server

So far I've been using the format below for creating/updating tables
IF EXISTS (SELECT 1 FROM sysobjects WHERE name = 'table_name' AND type = 'U')
DROP TABLE [dbo].[table_name]
GO
CREATE TABLE [dbo].[table_name]()
GO
But recently I came across a case where two schemas have a table with the same name. How can I check if the table exists in a specific schema? Its only the partSELECT 1 FROM sysobjects WHERE name = 'table_name' AND type = 'U' that needs fixing, I've changed the rest to:
IF EXISTS (SELECT 1 FROM sysobjects WHERE name = 'table_name' AND type = 'U')
DROP TABLE [schema_name].[table_name]
GO
CREATE TABLE [schema_name].[table_name]()
GO
My current server version is 2008R2 so I would prefer answers that also work for that version. I have many other checks is done this way so I don't really want to completely change this pattern.

TRY
IF OBJECT_ID('[schema_name].[table_name]') IS NOT NULL
DROP TABLE [schema_name].[table_name]
GO

You could use the schemas object as well. For example:
IF EXISTS (SELECT 1
FROM sys.tables t
JOIN sys.schemas s ON t.schema_id = s.schema_id
WHERE s.[name] = N'schema_name'
AND t.name = N'table_name'
AND t.type = 'U')
DROP TABLE [schema_name].[table_name];
GO

Use this syntax.
DROP TABLE IF EXISTS [schema_name].[table_name]

Related

Is there a way to check if an object is a table or a view in SQL Server?

I have a view that I am changing to a table in SQL Server.
I am dropping the view and then the next part of my code I am establishing the table.
My code works the first time I run it (when the object is a view), but when I need to run it multiple times, I get this error:
Cannot use DROP VIEW with 'engineer.Well' because 'engineer.Well' is a table. Use DROP TABLE.
I've been looking online but cannot find a way to check if an object is a table or a view, and the subsequently drop the object.
Any advice would be greatly appreciated.
Right now it looks like this,
IF OBJECT_ID('engineer.well') IS NOT NULL
BEGIN
DROP TABLE [engineer].[Well]
PRINT '<<< DROPPED TABLE Vendor >>>'
END
I am playing around with a way to check if the object is a table and then drop it, or check if it is a view then drop it.
You can query the system views.
DECLARE #Type varchar(2)
SELECT #Type = type
FROM sys.objects o
JOIN sys.schemas s ON o.schema_id = s.schema_id
WHERE o.name = 'well'
AND s.name = 'engineer'
IF #Type = 'U'
BEGIN
DROP TABLE [engineer].[Well]
PRINT '<<< DROPPED TABLE Vendor >>>'
END
IF #Type = 'V'
BEGIN
DROP VIEW [engineer].[Well]
PRINT '<<< DROPPED VIEW Vendor >>>'
END
OBJECTPROPERTY(OBJECT_ID('name'), 'IsView')
https://learn.microsoft.com/en-us/sql/t-sql/functions/objectproperty-transact-sql?view=sql-server-2017
or
SELECT id, type FROM sysobjects where id=OBJECT_ID('objectName')
You can query sys.objects table:
select type_desc, * from sys.objects where object_id = object_id('[dbo].[DimDates]')

'IF' does not prevent error, but only if it has already executed

I'm trying to move a column from one table to another (here's the post for that),
However this runs as a task, and may run after it has already completed so I need a clause that prevents the logic from running again. I thought I could achieve this with an IF:
IF EXISTS (
SELECT *
FROM sys.columns
WHERE object_id = OBJECT_ID(N'Table_A')
AND name = 'internalID'
)
BEGIN
UPDATE Table_B
SET b.internalID = a.internal_ID
FROM Table_B b INNER JOIN
Table_A a
ON a.id = b.FK_toTableA;
ALTER TABLE Table_A DROP COLUMN internalID;
END
However, I get an error at
SET b.internalID = a.internal_ID
The error is:
Invalid column name 'internalID'.
But Only If a.internalID doesn't exist anymore.
I had to use EXEC sp_executesql:
IF EXISTS (
SELECT *
FROM sys.columns
WHERE object_id = OBJECT_ID(N'Table_A')
AND name = 'internalID'
)
BEGIN
EXEC sp_executesql N'UPDATE Table_B
SET b.internalID = a.internal_ID
FROM Table_B b INNER JOIN
Table_A a
ON a.id = b.FK_toTableA';
ALTER TABLE Table_A DROP COLUMN internalID;
END
I guess because SQL Server complies the whole thing - even that stuff bypassed via conditional logic - before running the script.
Here's a good article about what sql_executesql does, compared to EXEC, but it basically boils down to more injection prevention.

Drop column if exists in SQL Server 2008 r2

I am using SQL Server 2008 R2.
I want to drop the column if it is already exists in the table else not throw any error.
Tried:
ALTER TABLE Emp
DROP COLUMN IF EXISTS Lname;
Error:
Incorrect syntax near the keyword 'IF'.
By searching I came to know that, this option is available from 2016.
What is the alternative in the SQL Server 2008 R2?
IF EXISTS (SELECT 1
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = 'Emp'
AND COLUMN_NAME = 'Lname'
AND TABLE_SCHEMA='DBO')
BEGIN
ALTER TABLE Emp
DROP COLUMN Lname
END
GO
From the MSDN social documentation, we can try:
IF EXISTS (SELECT 1 FROM sys.objects o
INNER JOIN sys.columns c ON o.object_id = c.object_id
WHERE o.name = 'Emp' AND c.name = 'Lname')
ALTER TABLE dbo.Emp DROP COLUMN Lname;
I followed this way.
IF COL_LENGTH (N'{Your_TableName}', N'{Your_ColumnName}') IS NOT NULL
BEGIN
ALTER TABLE {Your_TableName}
DROP COLUMN {Your_ColumnName};`
END
GO

How do you truncate all tables except lookup tables in a database using TSQL?

What is the best way to remove all the data from all the tables except look-up tables data using TSQL in SQL Server 2012 and downwards?
I would like the TSQL identify and exclude look-up tables then create truncate table statements for the other tables.
** There is almost a similar question but it truncates all the tables.
Both Lookup Tables and non Lookup tables are similar in technical characteristics. Only functionally they are different. Hence there won't be specific criteria to differentiate both of them.
Unless you set yourself up to be able to do this from the design standpoint, e.g. putting all "Lookup" tables in a "lkup" schema, or something of that nature, I don't think there's a way to do this. As someone already mentioned, a lookup table is a table like any other.
I would automate using DELETE by deleting in the right order first of all (dependencies)
1) pass the table name
2) disable your foreign keys
3) empty DELETE ALL the table
4) re-enable they keys.
this way you can control passing the table names you want "truncated" with a conditional.
or will it matter then:
ALTER PROCEDURE
up_ResetEntireDatabase
#IncludeIdentReseed BIT,
#IncludeDataReseed BIT
AS
EXEC sp_MSForEachTable 'ALTER TABLE ? NOCHECK CONSTRAINT ALL'
EXEC sp_MSForEachTable 'DELETE FROM ?'
IF #IncludeIdentReseed = 1
BEGIN
EXEC sp_MSForEachTable 'DBCC CHECKIDENT (''?'' , RESEED, 1)'
END
EXEC sp_MSForEachTable 'ALTER TABLE ? CHECK CONSTRAINT ALL'
IF #IncludeDataReseed = 1
BEGIN
-- Populate Core Data Table Here
END
GO
And then once ready the execution is really simple:
EXEC up_ResetEntireDatabase 1, 1
I'm not sure if you mean lookup tables like one that could drive this.
build a simple table that has names of each of the database tables and create columns you could modify if necessary before you execute the script.
the columns could just be flags that tell the script whether or not to truncate that table or other.
that way you (script) will know dependencies as it reads table names. an index is not needed if you keep table order static in record number order.
just another maintenance script.
So you want to truncate the tables that have foreign keys but keep the references tables alone. This should do it.
WITH CTE_fks
AS
(
SELECT obj.name AS FK_NAME,
sch1.name AS [table_schema],
tab1.name AS [table_name],
col1.name AS [column],
sch2.name AS [ref_table_schema],
tab2.name AS [referenced_table],
col2.name AS [referenced_column]
FROM sys.objects obj
INNER JOIN sys.foreign_key_columns fkc
ON obj.object_id = fkc.constraint_object_id
INNER JOIN sys.tables tab1
ON tab1.object_id = fkc.parent_object_id
INNER JOIN sys.schemas sch1
ON tab1.schema_id = sch1.schema_id
INNER JOIN sys.columns col1
ON col1.column_id = parent_column_id AND col1.object_id = tab1.object_id
INNER JOIN sys.tables tab2
ON tab2.object_id = fkc.referenced_object_id
INNER JOIN sys.schemas sch2
ON tab2.schema_id = sch2.schema_id
INNER JOIN sys.columns col2
ON col2.column_id = referenced_column_id AND col2.object_id = tab2.object_id
)
SELECT 'TRUNCATE TABLE ' + QUOTENAME(A.TABLE_SCHEMA) + '.' + QUOTENAME(A.table_name) + ';'
FROM INFORMATION_SCHEMA.TABLES A
LEFT JOIN CTE_fks B
ON A.TABLE_NAME = B.referenced_table
AND A.TABLE_SCHEMA = B.ref_table_schema
WHERE A.TABLE_TYPE = 'BASE TABLE'
AND A.TABLE_NAME != 'sysdiagrams'
AND B.table_name IS NULL

Add a column to a table, if it does not already exist

I want to write a query for MS SQL Server that adds a column into a table. But I don't want any error display, when I run/execute the following query.
I am using this sort of query to add a table ...
IF EXISTS (
SELECT *
FROM sys.objects
WHERE OBJECT_ID = OBJECT_ID(N'[dbo].[Person]')
AND TYPE IN (N'U')
)
But I don't know how to write this query for a column.
You can use a similar construct by using the sys.columns table io sys.objects.
IF NOT EXISTS (
SELECT *
FROM sys.columns
WHERE object_id = OBJECT_ID(N'[dbo].[Person]')
AND name = 'ColumnName'
)
IF COL_LENGTH('table_name', 'column_name') IS NULL
BEGIN
ALTER TABLE table_name
ADD [column_name] INT
END
Another alternative. I prefer this approach because it is less writing but the two accomplish the same thing.
IF COLUMNPROPERTY(OBJECT_ID('dbo.Person'), 'ColumnName', 'ColumnId') IS NULL
BEGIN
ALTER TABLE Person
ADD ColumnName VARCHAR(MAX) NOT NULL
END
I also noticed yours is looking for where table does exist that is obviously just this
if COLUMNPROPERTY( OBJECT_ID('dbo.Person'),'ColumnName','ColumnId') is not null
Here's another variation that worked for me.
IF NOT EXISTS (SELECT 1
FROM INFORMATION_SCHEMA.COLUMNS
WHERE upper(TABLE_NAME) = 'TABLENAME'
AND upper(COLUMN_NAME) = 'COLUMNNAME')
BEGIN
ALTER TABLE [dbo].[Person] ADD Column
END
GO
EDIT:
Note that INFORMATION_SCHEMA views may not always be updated, use SYS.COLUMNS instead:
IF NOT EXISTS (SELECT 1
FROM SYS.COLUMNS....
IF NOT EXISTS (SELECT * FROM syscolumns
WHERE ID=OBJECT_ID('[db].[Employee]') AND NAME='EmpName')
ALTER TABLE [db].[Employee]
ADD [EmpName] VARCHAR(10)
GO
I Hope this would help. More info
When checking for a column in another database, you can simply include the database name:
IF NOT EXISTS (
SELECT *
FROM DatabaseName.sys.columns
WHERE object_id = OBJECT_ID(N'[DatabaseName].[dbo].[TableName]')
AND name = 'ColumnName'
)
IF NOT EXISTS (SELECT 1 FROM SYS.COLUMNS WHERE
OBJECT_ID = OBJECT_ID(N'[dbo].[Person]') AND name = 'DateOfBirth')
BEGIN
ALTER TABLE [dbo].[Person] ADD DateOfBirth DATETIME
END

Resources