Table "already exists" after dropping with if exists - sql

I got a pretty complex SQL that finally forced me to use a temp table to work around.
Essentially it looks like this:
;IF EXISTS(SELECT * FROM sys.tables WHERE SCHEMA_NAME(schema_id) LIKE 'dbo' AND name like '#MYTEMPTABLE')
DROP TABLE #MYTEMPTEBLE;
WITH cte AS ...
SELECT * INTO #MYTEMPTABLE FROM cte
SELECT * FROM #MYTEMPTABLE WHERE [conditions]
DROP TABLE #MYTEMPTABLE;
However, I get an error message saying an object with the name #MYTEMPTABLE already exists in the database after a call with an error (which is rather likely if the customer/tester screws up some data).

It might DROP TABLE fail on your check condition, it might check from TempDB.INFORMATION_SCHEMA.COLUMNS table instead of sys.tables table
SELECT * FROM TempDB.INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME IN (
SELECT NAME
FROM TempDB.SYS.TABLES
WHERE OBJECT_ID=OBJECT_ID('TempDB.dbo.#MYTEMPTEBLE')
);
sqlfiddle
If your SQL server version was higher than 2016, you can try to use DROP TABLE IF EXISTS
DROP TABLE IF EXISTS #MYTEMPTEBLE;
WITH cte AS ...
SELECT * INTO #MYTEMPTABLE FROM cte
SELECT * FROM #MYTEMPTABLE WHERE [conditions]
if your SQL server version didn't support that, you can check OBJECT_ID IS NOT NULL which represnt temp table exists in your system
IF OBJECT_ID('TempDB..#MYTEMPTEBLE') IS NOT NULL
DROP TABLE #MYTEMPTEBLE;

Related

Create a temp table with pre-filled columns

Im trying to create a temp table #TempTable with columns. There are many columns and I do not want to type them all out by hand. Is there a way to pre-fill, if that makes sense?
Instead of
CREATE #TempTable (col1, col2 ... col1000) -- Im not saying we have 1000
But doing:
CREATE #TempTable (SELECT column_name
from information_schema.columns where table_name = 'OriginalTable')
Is this possible? Im using MS SQL.
You can do SELECT . . . INTO :
SELECT ot.* INTO #TempTable
FROM OriginalTable ot
WHERE 1 = 0;
Note : When using the SELECT . . . INTO statement, the #TempTable must not already exist.
When creating a temp table, it's good to clean up before creating it. repeating this step will cause an error if the table already exists
IF OBJECT_ID('tempdb..#tmp') IS NOT NULL
DROP TABLE #tmp
select *
into #tmp
from OriginalTable
One way of doing -
select top 0 * into #TempTable from OriginalTable
The above creates an empty copy of temp table
If you don't want to specify *(wildcard) and want specific columns from OriginalTable to be created in your temporary table -
select top 0 col1,col2,col3 into #TempTable from OriginalTable

Drop indexes or alter

I am trying to drop pk constraint and drop index on the target table in informatica, these below statements are working first time successfully.
IF EXISTS (SELECT Name FROM sysindexes WHERE Name = 'xyz')
DROP INDEX [xyz] ON [dbo].[Table_Name];
IF EXISTS (SELECT Name FROM sysindexes WHERE Name = 'xyz')
ALTER TABLE [dbo].[Table_Name] DROP CONSTRAINT [xyz];
But if I run the same query a second time it is giving an error:
Cannot drop the index 'dbo.Table_Name.xyz', because it does not exist or you do not have permission
I need an If ... Else statement syntax like if exists drop else end or success something.
The likely cause for this is that you might have more than one index named xyz on your database. Your IF EXISTS SELECT statement is not taking into consideration which table xyz is on.
You can check for this condition yourself by running the select statement by itself.
Try changing your query to the following to limit the scope:
If Exists
(
Select *
From sys.indexes
Where name = 'xyz'
And Object_Id = Object_Id('dbo.Table_Name')
)
Drop Index xyz On dbo.Table_Name;
One way to get around this issue is to trick the parser:
IF EXISTS (SELECT * FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS WHERE SCHEMA_NAME = 'dbo' AND TABLE_NAME = 'Table_Name' AND CONSTRAINT_TYPE = 'PRIMARY KEY' AND CONSTRAINT_NAME = 'xyz')
BEGIN
EXEC('ALTER TABLE [dbo].[Table_Name] DROP CONSTRAINT [xyz]')
END

How do I add/remove columns using SQL Server 2012 Management Studio

When I execute
exec sp_columns TABLE_NAME
it returns many columns, I need to display specific columns only and add a description column as well.
Is there anyway for me to customize the table to do this?
I am using SQL Server 2012 Management Studio
With SSMS you can use the table designer to add columns fairly easily. In the server browser, find your table, right click, and "Design."
--Check if column does not exists, if yes than add.
IF NOT EXISTS (
SELECT *
FROM sys.columns
WHERE [name] = N'Column_Name'
AND [object_id] = OBJECT_ID(N'Table_Name')
)
BEGIN
ALTER TABLE Table_Name ADD Column_Name Type;
END
-- Similarly for removing column
--Check if column does exists, if yes than add.
IF EXISTS (
SELECT *
FROM sys.columns
WHERE [name] = N'Column_Name'
AND [object_id] = OBJECT_ID(N'Table_Name')
)
BEGIN
ALTER TABLE Table_Name Remove Column_Name;
END
GO
select column_name, table_name from INFORMATION_SCHEMA.COLUMNS where TABLE_NAME like '%table name%' and column_name
in
(
'column1',
'column2'
)

SQL query for finding all tables ROWS with two columns in them

I have a DataBase with around +100 tables, like half of tables have column A & column B.
My question is, Can I query all tables that have this columns with a specific values e.g.
SELECT * FROM DATABASE
WHERE
EACHTABLE HAS COLUMN A = 21 //only if table has columns and then values
AND
COLUMN B = 13
I am not sure how exact I will do it, nothing is coming up on google either
You can use the undocumented MS stored procedure sp_MSforeachtable, if you fancy living life recklessly:
create table T1 (
ColumnA int not null,
ColumnB int not null
)
go
create table T2 (
ColumnA int not null,
Column2 int not null
)
go
create table T3 (
Column1 int not null,
ColumnB int not null
)
go
create table T4 (
ColumnA int not null,
ColumnB int not null
)
go
insert into T1 values (1,2);
insert into T2 values (3,4);
insert into T3 values (5,6);
insert into T4 values (7,8);
go
create table #Results (TableName sysname,ColumnA int,ColumnB int)
exec sp_MSforeachtable 'insert into #Results select ''?'',ColumnA,ColumnB from ?',
#whereand = ' and syso.object_id in (select object_id from sys.columns where name=''ColumnA'') and syso.object_id in (select object_id from sys.columns where name=''ColumnB'')'
select * from #Results
drop table #Results
Result:
TableName ColumnA ColumnB
------------------------------------- ----------- -----------
[dbo].[T1] 1 2
[dbo].[T4] 7 8
By default, sp_MSforeachtable will, as its name implies, perform the same task for each table in the database. However, one optional parameter to this procedure, called #Whereand, can be used to modify the WHERE clause of the internal query that enumerates the tables in the database. It helps to know that this internal query has already established two aliases to some of the system views. o is an alias for sysobjects (the legacy system view). syso is an alias for sys.all_objects (a more modern system view).
Once sp_MSforeachtable has decided which tables to run against, it will execute the query given to it as its first parameter. But, it will replace ? with the schema and table name (? is the default replacement character. This can be changed as needed)
In this case, I chose to create a temp table, then have each selected table store its results into this temp table, and after sp_MSforeachtable has finished running, to select the combined results out with no further processing.
There is a similar (and similarly undocumented) procedure called sp_MSforeachdb which will access each user database on the server. These can even be combined (although you have to be careful with doubling up ' quote characters twice, at times). However, there's no equivalent sp_MSforeachcolumn.
Try this:
select t.name from sys.objects t inner join sys.columns c
on t.name=OBJECT_NAME(c.object_id)
where t.type='U'
and c.name in('col1','col2')
group by t.name
having COUNT(*) = 2
order by 1
Then you just loop through all the tables and fine the values for these columns.
Like
Declare #out TABLE(tblname varchar(100))
if exists(select * from tbl1 where col1='21' and col2='22')
BEGIN
INSERT INTO #out
select tbl1
END
You can try like this using dynamic query.
select 'select * from '+table_name+ ' where'+column_name+'=21'
from information_schema.columns where column_name = 'A'
I suggest to use two steps:
First, find out all tables in your database that have these two columns and use it for a temporal derived table. For I am not an expert in SQL-Server 2008 I recommend to have a look at the whitepages.
The expression might look like this:
SELECT tablename
FROM information_schema.tables sdbt
WHERE "column a" IN
(SELECT columns
FROM information_schema.columns col
WHERE col.tablename = sdbt.tablename)
Second, use a expresssion to filter the results according to your demanded values.
This command should do the trick in one go, only for column A, amend accordingly to include any other columns you need:
exec sp_MSforeachtable
#command1=N'SELECT * FROM ? WHERE A = 21',
#whereand=' and o.name IN (SELECT TABLE_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE COLUMN_NAME = ''A'') '

Drop table if exist with similar name in two schema

I use this command to drop a table in sql-server 2008
IF EXISTS(SELECT name FROM [DBName]..sysobjects WHERE name = N'TableName' AND xtype='U')
DROP TABLE [DBName].[SchemaName].[TableName];
But now I have 2 tables with same name in different schema:
[DBName].[Schema1].[Members]
And
[DBName].[Schema2].[Members]
So, what is your suggestion for check if exist this tables? How can I check table names with schema?
UPDATE:
OK, there is 3 different answers and all of them worked, so I don't know which one is better, does any one know about use object_id or sys.tables?
IF EXISTS(
SELECT *
FROM [DBName].sys.tables t
JOIN [DBName].sys.schemas s
ON t.SCHEMA_ID = s.schema_id
WHERE
t.name = N'TableName' AND t.type='U'
AND s.NAME = 'SchemaName'
)
DROP TABLE [DBName].[SchemaName].[TableName];
Update:
object_id in sys.tables is the same as object_id in sysobjects for the same table. And is completely the same as function OBJECT_ID returns for the same table name. See the following illustrating examples.
So, you may simplify the query:
IF exists
(
SELECT *
FROM DBName.sys.tables
WHERE object_id = OBJECT_ID('[DBName].[SchemaName].[TableName]')
AND type = 'U'
)
DROP TABLE [DBName].[SchemaName].[TableName];
or in this way:
IF exists
(
SELECT *
FROM DBName.sys.objects
WHERE object_id = OBJECT_ID('[DBName].[SchemaName].[TableName]')
AND type = 'U'
)
DROP TABLE [DBName].[SchemaName].[TableName];
or for sql2000-styled tables:
IF exists
(
SELECT *
FROM DBName..sysobjects
WHERE object_id = OBJECT_ID('[DBName].[SchemaName].[TableName]')
AND xtype = 'U'
)
DROP TABLE [DBName].[SchemaName].[TableName];
Use this:
IF EXISTS
(
SELECT *
FROM sys.objects
WHERE object_id = OBJECT_ID(N'[DBName].[Schema1].[Member]')
AND type in (N'U')
)
PRINT 'Yes'
ELSE
PRINT 'No';
Don't use sysobjects. Use the modern system views in the sys schema (introduced in 2005):
select * from sys.tables
where
schema_id = SCHEMA_ID('Schema1') and
name='tablename'
As soon as you have one "modern" schema in a 2005 or later database, you cannot reliably use sysobjects to match with schemas. If you only have "old" schemas (objects belonging to users and roles), you may be able to query based on user_id.
Wouldn't it be simplest just to:
IF object_id('[schema].[table]') > 0
DROP TABLE [schema].[table]
For non existent tables object_id() returns NULL
For some system tables it returns a negative int