Dropping and recreating databases in Microsoft SQL Server - sql-server

I am experimenting and learning with Microsoft SQL Server 2008 R2 SP1.
I have a database where I made many experiments. Now I would like to drop and recreate it.
So I extract the creation script from database, I delete it and I use the script to recreate it.
To my surprise, all the tables, keys etc are still there.
How do I drop the database, so that I can rebuild the database from scratch?

USE master
IF EXISTS(select * from sys.databases where name='yourDBname')
DROP DATABASE yourDBname
CREATE DATABASE yourDBname

+1 to AnandPhadke for his part of the code
This code will close all active connections to the database and then drop it
WHILE EXISTS(select NULL from sys.databases where name='YourDBName')
BEGIN
DECLARE #SQL varchar(max)
SELECT #SQL = COALESCE(#SQL,'') + 'Kill ' + Convert(varchar, SPId) + ';'
FROM MASTER..SysProcesses
WHERE DBId = DB_ID(N'YourDBName') AND SPId <> ##SPId
EXEC(#SQL)
DROP DATABASE [YourDBName]
END
GO
CREATE DATABASE YourDBName
GO

SQL Server 2016 (and above) support one line and atomic(?) syntax DROP DATABASE IF EXISTS database_name
REF: https://msdn.microsoft.com/en-us/library/ms178613.aspx

Requiring the DBName to be typed more than once is error prone, at some point it'll be executed with inconsistent entries and unintended consequences.
The answers from AnandPhadke or Pierre with variable support would be preferred for me.
DECLARE #DBName varchar(50) = 'YourDatabaseName'
USE master
IF EXISTS(select * from sys.databases where name= #DBName)
EXEC('DROP DATABASE ' + #DBName)
EXEC('CREATE DATABASE ' + #DBName)
or
DECLARE #DBName varchar(50) = 'YourDatabaseName'
WHILE EXISTS(select NULL from sys.databases where name = #DBName )
BEGIN
DECLARE #SQL varchar(max)
SELECT #SQL = COALESCE(#SQL,'') + 'Kill ' + Convert(varchar, SPId) + ';' FROM MASTER..SysProcesses WHERE DBId = DB_ID(#DBName) AND SPId <> ##SPId
EXEC(#SQL)
EXEC('DROP DATABASE ' + #DBName)
END
GO

I extract the creation script from database
This extract the creation script for everything in the database (tables, keys etc). If you simply want to create an empty database, just run CREATE DATABASE <dbname>

This works best for me:
if exists (select name from sys.databases where name='YourDBName')
alter database YourDBName set single_user with rollback immediate
go
if exists (select name from sys.databases where name='YourDBName')
drop database YourDBName

Related

How to drop a database if a variable with its logical name exists in SQL Server?

I created a variable containing the logical name of a database, and drop it if this is present in my LocalDB.
The problem that I am facing in my current code is that it only searches in the physical names of the existing databases.
(I have a database with the logical name 'Development' which does not get removed).
DECLARE #dbname nvarchar(128)
SET #dbname = 'Development'
IF(EXISTS(SELECT NULL FROM sys.databases
WHERE ('[' + name + ']' = #dbname OR name = #dbname )))
BEGIN
DECLARE #sql VARCHAR(MAX)
SELECT #sql = COALESCE(#sql,'') + 'Kill ' + Convert(varchar, SPId) + ';'
FROM MASTER..SysProcesses
WHERE DBId = DB_ID(#dbname) AND SPId <> ##SPId
EXEC(#sql)
EXEC('DROP DATABASE ' + #dbname);
PRINT 'Existing database removed'
END
ELSE
BEGIN
PRINT 'Database not present';
END
The result I get is the print 'Database not present' and the db is not removed.
What I would like is a deleted database (.mdf and .ldf)
The user executing the query probably does not have permissions to see the database.
If the caller of sys.databases is not the owner of the database and
the database is not master or tempdb, the minimum permissions required
to see the corresponding row are ALTER ANY DATABASE or the VIEW ANY
DATABASE server-level permission, or CREATE DATABASE permission in the
master database. The database to which the caller is connected can
always be viewed in sys.databases.
Taken from https://learn.microsoft.com/en-us/sql/relational-databases/system-catalog-views/sys-databases-transact-sql?view=sql-server-2017
Try running the below query in SSMS to check if you can see your database.
SELECT * FROM sys.databases
The database doesn't have the logical name "development". One of the files it contains has that logical name.
To get the database name corresponding to the logical file name you can use
SELECT DB_NAME(database_id)
FROM sys.master_files
WHERE name = 'Development'
And then assign that to #dbname - there may be multiple results. There is no guarantee that logical file name is unique across databases

SQL Server 2016 Change Object Owner

I've inherited a SQL 2008 dbase in which all of its objects are prefixed with the name of the developer as owner, i.e. ownername.sp_get_all_users.
I've restored the dbase onto SQL Server 2016 Express Edition.
There are several hundred dbase objects, is there a way to automate changing the object owners to dbo rather than manually editing each object?
I've tried the following but apparently you can no longer make ad-hoc changes to objects since SQL Server 2005?
SELECT * from sysobjects where uid = user_id('UseNAme')
declare #Return int
exec #Return = sp_configure 'allow updates', '1'
SELECT #Return as 'Returned Code'
GO
reconfigure WITH OVERRIDE
GO
DECLARE #Rows int, #Error int
BEGIN TRANSACTION
update sysobjects set uid = user_id('dbo') where uid = user_id('UseNAme')
SELECT #Error = ##Error, #Rows = ##RowCount
SELECT #Rows as '#Rows'
IF #Rows > 0
BEGIN
SELECT #Rows AS '#Rows'
COMMIT TRANSACTION
END
else
BEGIN
SELECT #Error AS 'Error #'
ROLLBACK TRANSACTION
END
exec sp_configure 'allow updates', '0'
reconfigure WITH OVERRIDE
go
Any help most appreciated.
You have to use Alter Schema...
ALTER SCHEMA oldschemaname TRANSFER dbo.Address;
To Automate use below
this will change all tables which have a schema other than system to dbo,note if you have two tables in different schema,they can't exist in same schema
select *,row_number() over (order by (select null)) as rownum
into #tables
from information_Schema.tables
where table_schema in (select name from sys.schemas
where name not in ('dbo','guest','INFORMATION_SCHEMA','sys') and principal_id <16384
)
now move
declare #min int,#max int
select #min=min(rownum),#max=max(rownum)
from #tables
declare #tblname varchar(255),#schemaname sysname
declare #sql varchar(max)
while #min<=#max
Begin
select #tblname=table_name,#schemaname=table_schema from
#tables where rownum=#min
set #sql='alter schema dbo transfer '+ #schemaname+'.'+#tblname
--print #sql
exec(#sql)
Set #min=#min+1
End
sp_change object owner as per documentation states..
This stored procedure only works with the objects available in MicrosoftSQL Server 2000. This feature will be removed in a future version of Microsoft SQL Server. Avoid using this feature in new development work, and plan to modify applications that currently use this feature. Use ALTER SCHEMA or ALTER AUTHORIZATION instead. sp_changeobjectowner changes both the schema and the owner. To preserve compatibility with earlier versions of SQL Server, this stored procedure will only change object owners when both the current owner and the new owner own schemas that have the same name as their database user names.
Use this sp_changeobjectowner
As explained here MSDN
For example: EXEC sp_changeobjectowner 'YourObject', 'dbo'
You can use this to alter schema statement for newer SQL Server DBS
declare #sql varchar(8000), #table varchar(1000), #oldschema varchar(1000), #newschema varchar(1000)
set #oldschema = 'dbo'
set #newschema = 'exe'
while exists(select * from sys.tables where schema_name(schema_id) = #oldschema)
begin
select #table = name from sys.tables
where object_id in(select min(object_id) from sys.tables where schema_name(schema_id) = #oldschema)
set #sql = 'alter schema ' + #newschema + ' transfer ' + #oldschema + '.' + #table
exec(#sql)
end
Your general idea of looping through the objects owned by the developer is a good idea (assuming you've tested the heck out of it). I'd suggest using the ALTER AUTHORIZATION command instead MSDN Doc
In addition to the advice above, the following changes the owner of SPs:
Declare #sql varchar(8000),
#table varchar(1000),
#oldschema varchar(1000),
#newschema varchar(1000)
set #oldschema = 'developername'
set #newschema = 'dbo'
while exists(select * from information_schema.routines where routine_type = 'PROCEDURE' and routine_schema = #oldschema )
begin
select #table = SPECIFIC_NAME from information_schema.routines
where SPECIFIC_NAME in(select SPECIFIC_NAME from information_schema.routines where routine_type = 'PROCEDURE' and routine_schema = #oldschema)
set #sql = 'alter schema ' + #newschema + ' transfer ' + #oldschema + '.' + #table
exec(#sql)
end

SQL Studio Prepared Statement

I am doing work for a company that stores each of their client's info in a different database. When a table needs modification, I have to go to each database and run the ALTER TABLE script. Is there a way I can use a prepared statement to run through all 100+ DBO names?
ALTER TABLE ?.dbo.profileTable
ADD COLUMN profileStatus int
where ? = 'CompanyA, CompanyB, CompanyC' or something similar?
Use Sp_MSforeachdb
EXECUTE master.sys.sp_MSforeachdb 'USE [?]; alter query'
[?] is used as a placeholder for the heretofore unspecified database name
You can modify the query as per your needs ,to exclude system databases use like below..
EXECUTE master.sys.sp_MSforeachdb 'USE [?]; IF DB_ID(''?'') > 4 begin yourquery end'
This will exclude any database that does not have the table you are looking for including system databases.
Declare #TableName Varchar(8000) = 'ProfileTable'
Declare #Sql Varchar(8000)
Select #Sql = Stuff(
(Select ';', 'Alter Table ' + Name + SqlText
From sys.databases
Cross Apply (Select '.dbo.profileTable ADD profileStatus int' SqlText) CA
Where Case When State_Desc = 'ONLINE'
Then Object_Id (QuoteName(Name) + '.[dbo].' + #TableName, 'U')
End Is Not Null
FOR XML PATH('')
),1,1,'')
Exec (#Sql)
This ? before is database ([database].[schema].[table]). Thus you can use sp_MSforeachdb or, as I prefer, use sys.databases view to prepare dynamic queries.
Beware, both methods can interfere with system databases.
Take a look at this solution:
DECLARE #query nvarchar(MAX)='';
SELECT #query = #query + 'USE '+QUOTENAME(name)+';ALTER TABLE dbo.profileTable ADD profileStatus int;'
FROM sys.databases
WHERE OBJECT_ID(QUOTENAME(name)+'.dbo.profileTable', 'U') IS NOT NULL
EXEC(#query)
It adds column col1 int to each dbo.profileTable in every database.

Find All Empty Tables Named MAP_ALERT In All Databases On Server

We perform studies at my job, and each study has its own database. All the study databases are on the same server, and eaxch has a table named MAP_ALERT.
I need to find all MAP_ALERT tables that contain no data, for all the study databases. I found this page that tells how to find empty tables in one database: Select all empty tables in SQL Server - how can I adapt this to find ALL empty tables named MAP_ALERT in ALL database on a given server?
You can use dynamic sql here to help you out. This is querying the system tables for each database. This will even properly handle databases that don't have that table.
declare #SQL nvarchar(MAX)
set #SQL = '';
create table #Results
(
DBName sysname
)
select #SQL = #SQL + 'if exists(select * from ' + name + '.sys.tables where name = ''MAP_ALERT'') insert #results (DBNAME) select ''' + name + ''' from ' + name + '.dbo.MAP_ALERT having count(*) > 0;'
from sys.databases
--select #SQL
--uncomment the following when you have evaluated the dynamic sql and understand what query is going to run on your system
exec sp_executesql #SQL
select * from #Results

In sql server 2005, how do I change the "schema" of a table without losing any data?

I have a table that got into the "db_owner" schema, and I need it in the "dbo" schema.
Is there a script or command to run to switch it over?
In SQL Server Management Studio:
Right click the table and select modify (it's called "Design" now)
On the properties panel choose the correct owning schema.
ALTER SCHEMA [NewSchema] TRANSFER [OldSchema].[Table1]
Show all TABLE_SCHEMA by this select:
SELECT TABLE_SCHEMA, TABLE_NAME
FROM INFORMATION_SCHEMA.TABLES
You can use this query to change all schema for all tables to dbo table schema:
DECLARE cursore CURSOR FOR
SELECT TABLE_SCHEMA, TABLE_NAME
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_SCHEMA <> 'dbo'
DECLARE #schema sysname,
#tab sysname,
#sql varchar(500)
OPEN cursore
FETCH NEXT FROM cursore INTO #schema, #tab
WHILE ##FETCH_STATUS = 0
BEGIN
SET #sql = 'ALTER SCHEMA dbo TRANSFER ' + #schema + '.' + #tab
PRINT #sql
FETCH NEXT FROM cursore INTO #schema, #tab
END
CLOSE cursore
DEALLOCATE cursore
simple answer
sp_changeobjectowner [ #objname = ] 'object' , [ #newowner = ] 'owner'
you don't need to stop all connections to the database, this can be done on the fly.
A slight improvement to sAeid's excellent answer...
I added an exec to have this code self-execute, and I added a union at the top so that I could change the schema of both tables AND stored procedures:
DECLARE cursore CURSOR FOR
select specific_schema as 'schema', specific_name AS 'name'
FROM INFORMATION_SCHEMA.routines
WHERE specific_schema <> 'dbo'
UNION ALL
SELECT TABLE_SCHEMA AS 'schema', TABLE_NAME AS 'name'
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_SCHEMA <> 'dbo'
DECLARE #schema sysname,
#tab sysname,
#sql varchar(500)
OPEN cursore
FETCH NEXT FROM cursore INTO #schema, #tab
WHILE ##FETCH_STATUS = 0
BEGIN
SET #sql = 'ALTER SCHEMA dbo TRANSFER [' + #schema + '].[' + #tab +']'
PRINT #sql
exec (#sql)
FETCH NEXT FROM cursore INTO #schema, #tab
END
CLOSE cursore
DEALLOCATE cursore
I too had to restore a dbdump, and found that the schema wasn't dbo - I spent hours trying to get Sql Server management studio or visual studio data transfers to alter the destination schema... I ended up just running this against the restored dump on the new server to get things the way I wanted.
When I use SQL Management Studio I do not get the 'Modify' option, only 'Design' or 'Edit'. If you have Visual Studio (I have checked VS.NET 2003, 2005 & 2008) you can use the Server Explorer to change the schema. Right click on the table and select 'Design Table' (2008) or 'Open Table Definition' (2003, 2005). Highlight the complete "Column Name" column. You can then right click and select 'Property Pages' or Properties (2008). From the property sheet you should see the 'Owner' (2003 & 2005) or 'Schema' (2008) with a drop down list for possible schemas.
I use this for situations where a bunch of tables need to be in a different schema, in this case the dbo schema.
declare #sql varchar(8000)
;
select
#sql = coalesce( #sql, ';', '') + 'alter schema dbo transfer [' + s.name + '].[' + t.name + '];'
from
sys.tables t
inner join
sys.schemas s on t.[schema_id] = s.[schema_id]
where
s.name <> 'dbo'
;
exec( #sql )
;
You need to firstly stop all connections to the database, change the ownership of the tables that are 'db_owner' by running the command
sp_MSforeachtable #command1="sp_changeobjectowner ""?"",'dbo'"
where ? is the table name.

Resources