SQL: There is already an object named X in the database - sql

This is my entire code so far
select Region
into #C
from ResearchDB.dbo.tC
where Tier=0
But I already get an error:
There is already an object named '#C' in the database.
Now if I comment the line " into #C" out, it works perfectly. Whats going on??

I use two options: 1 (quick but temporary) - Just hit the Change Connection button in SSMS and reconnect without changing any of the details. This will re-establish your connections dropping your temporary tables in the process. Don't forget to reselect your database as it will default to Master or whatever your default database has been set as.
2. I have a SP that drops all temp tables for your current session ONLY and I add this line
EXEC dbf_DropTempTables
at the top of each piece of code I use that creates temp tables that I made need to rerun multiple times whilst troubleshooting. Here is the SP for reference:
`CREATE PROCEDURE dbf_DropTempTables
AS
-- drop all #temp tables for current session
begin
DECLARE #sql VARCHAR(60),
#name VARCHAR(60)
DECLARE dtt CURSOR
FOR SELECT SUBSTRING(t.name, 1, CHARINDEX('___', t.name) - 1)
FROM tempdb.sys.tables AS t
WHERE t.name LIKE '#%[_][_][_]%'
AND t.[object_id] = OBJECT_ID('tempdb..' + SUBSTRING(t.name, 1, CHARINDEX('___', t.name) - 1))
open dtt
fetch next from dtt into #name
while ##fetch_status <> -1
BEGIN
SELECT #sql = 'DROP TABLE ' + #name
EXEC ( #sql )
fetch next from dtt into #name
END
CLOSE dtt
deallocate dtt
END`

Related

Is there a way add auto increment in all tables from a specific database at once?

I am trying to add auto increment in all existing tables in a specific database, and I can do that going through the table design, flagging the identity option, but in this case I have to do it table per table, and there is a lot of tables. Is there a way to do that automatically?
Copied from my comments per request:
I don't believe you're going to find an automated option for doing this for multiple tables. The change script that SSMS creates when you do this in table designer is already doing a ton of work you'd have to recreate for any other solution. Frankly, I wouldn't trust myself to do it as correctly as SSMS.
However, if it were a large enough number of tables, I would create a completely new database with the corrected schema. Ensure that everything in the new database is present and correct. Then, set identity insert to on all tables in the new db, copy the data over, set all the identity inserts off, and then move the new db to the old db with DETACH/ATTACH or BACKUP/RESTORE. In other words, I'd literally rebuild the database from the ground up because old schema had been completely trashed. It would take a lot for me to decide to do that in a production system, however.
I'd only do the DETACH/ATTACH or BACKUP/RESTORE if I absolutely needed to change the database file names or database names. I'd actually prefer to just use the new database as a new database for the application. That would also mean I could swap back to the old database pretty quickly if I ran into trouble.
It can be done by using a 'cursor', but you need to have all the columns that you need to add auto increment to in the same name as ID
Declare #Table nvarchar(50), #script nvarchar(100)
DECLARE cur CURSOR FORWARD_ONLY READ_ONLY LOCAL FOR
SELECT TABLE_SCHEMA + '.' + TABLE_NAME as 'Table' FROM INFORMATION_SCHEMA.TABLES where TABLE_NAME not in ('sysdiagrams') -- You can exclude any table from this process by adding it on the where statement
OPEN cur
FETCH NEXT FROM cur INTO #Table
WHILE ##FETCH_STATUS = 0 BEGIN
-- The sql command to alter a Table and add Identity to it, you can change ID by any column in your tables
set #script = 'Alter Table '+ #Table +' ADD ID INT IDENTITY'
EXEC sp_executesql #script
FETCH NEXT FROM cur INTO #Table
END
CLOSE cur
DEALLOCATE cur
Edit 1 : According to what you asked for in the comment
Declare #Table nvarchar(50), #script nvarchar(100), #primarykey_name nvarchar(20)
DECLARE cur CURSOR FORWARD_ONLY READ_ONLY LOCAL FOR
SELECT TABLE_SCHEMA + '.' + TABLE_NAME as 'Table' FROM INFORMATION_SCHEMA.TABLES where TABLE_NAME not in ('sysdiagrams') -- You can exclude any table from this process by adding it here
OPEN cur
FETCH NEXT FROM cur INTO #Table
WHILE ##FETCH_STATUS = 0 BEGIN
-- Find Primary key for the current Table and set it to #primarykey_name
Set #primarykey_name = (SELECT c.NAME FROM sys.key_constraints kc INNER JOIN sys.index_columns ic ON kc.parent_object_id = ic.object_id and kc.unique_index_id = ic.index_id
INNER JOIN sys.columns c ON ic.object_id = c.object_id AND ic.column_id = c.column_id
WHERE kc.name='PK_'+ substring(#Table, 5, LEN(#Table)-4) and kc.type = 'PK')
-- The sql command to alter a Table and add Identity to the primarykey of each table
set #script = 'Alter Table '+ #Table +' ADD ' + #primarykey_name + ' INT IDENTITY'
print #script
--EXEC sp_executesql #script
FETCH NEXT FROM cur INTO #Table
END
CLOSE cur
DEALLOCATE cur

Copy SQL Server database for development but smaller

We have production database above 100Gig. I want to duplicate this database and give it to every developer to test its code, but the size is too large. Is there anyway I can backup just top 1000 rows with FK's and restore it to new DB? Or duplicate the DB first and delete all records from all tables, but keep 1000 rows with FK's or any other way to keep size below 5Gig.
I did search, but none of solutions were for tables having foreign keys.
Thanks,
Basheer
This the IDEA:
First:
Create new database:
Second:
Select small records only like:
select top 500 from allYourTables
then insert to each every table to your new Database Created.
Third:
Dump the new database and give to its every developer
Hope it helps:
Assuming that you have a new db_to_dev Database name and you are working to your current database:
This procedure will insert all the data from your working database, making sure that you had already a database created. db_to_dev:
Using Information_Schema you can select all your tables:
CREATE PROCEDURE PROC_TRANSFER_DATA #NUM_OF_RECORDS nvarchar(255) as
BEGIN
SET NOCOUNT ON;
DECLARE #message varchar(80), #tablename nvarchar(50);
Declare #sqlstmt nvarchar(255);
PRINT '-------- List of tables --------';
DECLARE Schema_cursor CURSOR FOR
SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES
OPEN Schema_cursor
FETCH NEXT FROM Schema_cursor INTO #tablename
IF ##FETCH_STATUS <> 0
PRINT ' <<None>>'
WHILE ##FETCH_STATUS = 0
BEGIN
SELECT #message = ' ' + #tablename
set #sqlstmt = 'select top ' + #NUM_OF_RECORDS + ' * into [db_to_dev].[dbo].['+ #tablename +'] from ' + #tablename;
EXEC sp_executesql #sqlstmt
PRINT #message
FETCH NEXT FROM Schema_cursor INTO #tablename
END
CLOSE Schema_cursor
DEALLOCATE Schema_cursor
END
To use:
With an option parameter:
EXEC PROC_TRANSFER_DATA '500'
Parameter value is depend on you if how many records you want to transfer into your new database db_to_dev.
This Stored Proc is tested.
Good luck
There are a number of projects on github which seek to do exactly that: make a subset that preserves referential integrity. Here is one such project:
https://github.com/18F/rdbms-subsetter

If given a list of SQL Server objects, how can I determine which databases each object resides in?

I have a list of over 200 databases objects. All of these are either tables, stored procedures and views.
All of these objects exist on a specific SQL Server, but I was not given a field specifying which database each object belong in.
Given a list of DB objects that exists somewhere on a specific server, how can I query the server to provide the containing database name for each object?
I had a similar issue, this is what worked for me:
-- List of objects .. store in a table somewhere with
-- a db column set to an empty string
create table tempdb.dbo._mylist ( name nvarchar(500), db nvarchar(500) )
insert tempdb.dbo._mylist values ('obj 1', '')
insert tempdb.dbo._mylist values ('obj 2', '')
-- Setup cursor for databases
DECLARE db_cursor CURSOR FOR
SELECT name from sys.databases WHERE [state] != 6 -- OFFLINE
-- Loop through cursor
OPEN db_cursor;
DECLARE #dbname sysname;
FETCH NEXT FROM db_cursor INTO #dbname;
WHILE (##FETCH_STATUS <> -1)
BEGIN;
-- added dbname to object list if found (joined using common collation)
EXECUTE ('use ' + #dbname + '; update l set db = db + '';' + #dbname + ''' from tempdb.dbo._mylist l join sysobjects o on o.name = l.name COLLATE SQL_Latin1_General_CP1_CI_AS;');
FETCH NEXT FROM db_cursor INTO #dbname;
END;
CLOSE db_cursor;
DEALLOCATE db_cursor;
GO
-- Select results
select name, db = isnull(stuff(db,1,1,''), '') from tempdb.dbo._mylist
-- Cleanup
drop table tempdb.dbo._mylist
You can write a script using the SP_MSFOREACHDB stored procedure to do this. You can find examples of this here This basically allows you to run a script against all the databases.
For Example, the statement below will allow you to search for a table name, and it will also return the associated databasename.
EXEC sp_Msforeachdb "USE [?]; SELECT '[?]' databaseName, * FROM sys.tables WHERE name = 'table_name'"

get sql log file name from within a script

We have a few test databases that we are throwing test indexes into and the log file gets bloated real quickly due to us dropping the contents of the table and repopulating it.
I have found, thanks to Stack Overflow, a few scripts and put them together to do what I need.
Here is the script:
USE SSSIndexes
GO
ALTER DATABASE SSSIndexes SET RECOVERY SIMPLE WITH NO_WAIT
GO
DBCC SHRINKFILE(N'SSSIndexes_Log', 1) <-- my issue is here
GO
The problem is the log file name. Is there a way to get the log file name without having to look it up manually and include it in the script to where this part is automated?
Btw, we never intend on restore this database. These are temporary indexes.
Thanks!
USE SSSIndexes
GO
ALTER DATABASE SSSIndexes SET RECOVERY SIMPLE WITH NO_WAIT
GO
DECLARE #Name NVARCHAR(50)
DECLARE cur CURSOR FOR
SELECT [name]
FROM [sys].[database_files]
where [type] = 1
OPEN cur
FETCH NEXT FROM cur INTO #Name
WHILE ##FETCH_STATUS = 0
BEGIN
DBCC SHRINKFILE(#Name, 1)
FETCH NEXT FROM cur INTO #Name
END
CLOSE cur
DEALLOCATE cur
You can use this to generate script for log file truncating of all databases on a specific server. To stick to specific databases use a filter.
SELECT
' USE [' + name + ']; GO
-- Truncate the log by changing the database recovery model to SIMPLE.
ALTER DATABASE [' + name + '] SET RECOVERY SIMPLE;
GO
-- Shrink the truncated log file to 1 MB.
DECLARE #logname varchar(128);
SELECT TOP 1 #logname=[name] FROM [' + name + '].[sys].[database_files] WHERE [type] = 1;
DBCC SHRINKFILE (#logname, 1);
GO
-- Reset the database recovery model.
ALTER DATABASE [' + name + '] SET RECOVERY FULL;
GO
' AS qry FROM master.dbo.sysdatabases
WHERE dbid > 6
WARNING!!!: YOU SHOULD ONLY DO THIS ON TEST DB SERVERS. Production DBs typically WANT to have FULL recovery mode. Test DBs you usually don't care.
Expanding on Abdul's answer (I had trouble getting it to show in new lines) and Dis' answers this finds the first db that has recovery FULL, sets it to simple and shrinks it... just keep clicking execute until it returns null
declare #dbname nvarchar(50)
declare #logfilename nvarchar(100)
select top(1) #dbname = name from sys.databases where recovery_model_desc <> 'SIMPLE' AND name <> 'tempdb'
declare #shrinkdb nvarchar(500)
set #shrinkdb = 'USE master
ALTER DATABASE [' + #dbname + '] SET RECOVERY SIMPLE
'
select #shrinkdb
execute sp_executesql #shrinkdb
set #shrinkdb = 'USE [' + #dbname + ']
DECLARE #Name NVARCHAR(50)
DECLARE cur CURSOR FOR
SELECT [name]
FROM [sys].[database_files]
where [type] = 1
OPEN cur
FETCH NEXT FROM cur INTO #Name
WHILE ##FETCH_STATUS = 0
BEGIN
DBCC SHRINKFILE(#Name, 1)
FETCH NEXT FROM cur INTO #Name
END
CLOSE cur
DEALLOCATE cur
'
select #shrinkdb
execute sp_executesql #shrinkdb

Programmatically replacing linked server references with local database references in SQL Server stored procs?

As a part of a scripted procedure I'm trying to programmatically update references to linked servers in stored procs. We have several references like this:-
SELECT foo, bar
FROM [Server].[Database].dbo.[Table]
Which I would like to translate to:-
SELECT foo, bar
FROM [Database].dbo.[Table]
I would like to do this entirely programmatically in a 'fire and forget' script across several databases.
The idea I have right now is to use metadata to find references to linked tables, read the text of each sp from metadata again, adjust each sp's text, then shove each block of updated text into an exec statement to rebuild 'em one-by-one.
I do wonder whether this will be a humongous pain however, so does anybody have any better ideas? I am open to using powershell if that could provide a better solution.
Thanks in advance!
Hopefully I am understanding the questions, but rather than removing or replacing [Server], I suggest one of two approaches:
Option 1: Don't change any of the
SPs. Instead, update the linked
server configuration to point a
different database, even the local
box.
Option 2: Don't change any of the
SPs. Instead, start using SQL Server
Aliases. SQL Server Aliases are
managed via the CliConfig utility and
are ultimately stored in the
registry. Thus, they can be applied
manually or via .reg script.
Basically, the SQL Server Alias
deciphers the server (along with
port) which is being referenced. If
you update the link server
configuration to reference the SQL
Server Alias rather than a specific
server, you can point your procedures
to different server (even the local server) whenever you
would like.
I hope it helps.
Your approach is the easiest, frankly. I had a similar issue earlier this year
Read sys.sql_modules
REPLACE the linked server text and CREATE -> ALTER
EXEC (#Result)
Here's a script to find all procs/functions/views that reference linked servers on a SQL 2005 instance - might be useful too:
USE master
GO
SET NOCOUNT ON;
--------------------------------------------------------------------
-- Test linked server connections
--------------------------------------------------------------------
BEGIN TRY DROP TABLE #Svrs; END TRY BEGIN CATCH END CATCH;
CREATE TABLE #Svrs
(
[Server] nvarchar(max),
[CanConnectAsDefault] bit
);
DECLARE #ServerName nvarchar(max), #RetVal int;
DECLARE Svrs CURSOR FAST_FORWARD READ_ONLY
FOR
SELECT ServerName = S.name
FROM sys.servers S;
OPEN Svrs;
FETCH NEXT FROM Svrs INTO #ServerName;
WHILE ##FETCH_STATUS = 0
BEGIN
BEGIN TRY
EXEC #RetVal = sys.sp_testlinkedserver #ServerName;
END TRY
BEGIN CATCH
SET #RetVal = sign(##error);
END CATCH;
INSERT INTO #Svrs
SELECT #ServerName
, CASE WHEN #RetVal = 0 THEN 1 ELSE 0 END;
FETCH NEXT FROM Svrs INTO #ServerName;
END;
CLOSE Svrs;
DEALLOCATE Svrs;
SELECT * FROM #Svrs
DROP TABLE #Svrs;
GO
--------------------------------------------------------------------
-- Report linked server references
--------------------------------------------------------------------
BEGIN TRY DROP TABLE #Refs; END TRY BEGIN CATCH END CATCH;
CREATE TABLE #Refs
(
[Server] nvarchar(max),
[Database] nvarchar(max),
[Schema] nvarchar(max),
[Object] nvarchar(max),
[Type] nvarchar(max)
);
DECLARE #DatabaseName nvarchar(max), #ServerName nvarchar(max), #SQL nvarchar(max);
DECLARE Refs CURSOR FAST_FORWARD READ_ONLY
FOR
SELECT DatabaseName = D.name
, ServerName = S.name
-- , ServerProvider = S.provider
-- , ServerSource = S.data_source
FROM sys.databases D
CROSS JOIN sys.servers S
WHERE D.name NOT IN ('master', 'tempdb', 'model', 'msdb', 'ReportServer', 'ReportServerTempDB');
OPEN Refs;
FETCH NEXT FROM Refs INTO #DatabaseName, #ServerName;
WHILE ##FETCH_STATUS = 0
BEGIN
SET #SQL = 'USE [' + #DatabaseName + '];
INSERT INTO #Refs
SELECT DISTINCT ''' + #ServerName + ''', ''' + #DatabaseName + ''', S.[name], O.[name], O.type_desc
FROM syscomments C
INNER JOIN sys.objects O ON C.id = O.[object_id]
LEFT JOIN sys.schemas S ON S.[schema_id] = O.[schema_id]
WHERE C.[TEXT] LIKE ''%[ ,~[( '''']' + #ServerName + '[ .,~])'''' ]%'' ESCAPE ''~'';'
PRINT 'Looking for ' + #ServerName + ' refs in ' + #DatabaseName -- + ': ' + #SQL;
EXEC sp_executesql #SQL;
FETCH NEXT FROM Refs INTO #DatabaseName, #ServerName;
END
CLOSE Refs;
DEALLOCATE Refs;
SELECT * FROM #Refs
DROP TABLE #Refs;
GO
--------------------------------------------------------------------
SET NOCOUNT OFF;
GO
This is not going to be a good idea for a production environment, but if you need a loopback linked server for dev purposes this worked for me:
EXEC sp_addlinkedserver #server = N'name_for_linked_server',
#srvproduct = N' ',
#provider = N'SQLNCLI',
#datasrc = N'name_of_my_sqlserver_instance',
#catalog = N'name_of_database'