SQL Server 2016 Change Object Owner - sql-server

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

Related

Create view that selects from identical tables from all databases on the server and can handle any time a new database is added to the server

I have a system that takes in Revit models and loads all the data in the model to a 2016 SQL Server. Unfortunately, the way the system works it created a new database for each model that is loaded. All the databases start with an identical schema because there is a template database that the system uses to build any new ones.
I need to build a view that can query data from all databases on the server but can automatically add new databases as they are created. The table names and associated columns will be identical across all databases, including data types.
Is there a way to pull a list of current database names using:
SELECT [name] FROM sys.databases
and then use the results to UNION the results from a basic SELECT query like this:
SELECT
[col1]
,[col2]
,[col3]
FROM [database].[dbo].[table]
Somehow replace the [database] part with the results of the sys.databases query?
The goal would be for the results to look as if I did this:
SELECT
[col1]
,[col2]
,[col3]
FROM [database1].[dbo].[table]
UNION
SELECT
[col1]
,[col2]
,[col3]
FROM [database2].[dbo].[table]
but dynamically for all databases on the server and without future management from me.
Thanks in advance for the assistance!
***Added Info: A couple suggestions using STRING_AGG have been made, but that function is not available in 2016.
Try this. It will automatically detect and include new databases with the specified table name. If a database is dropped it will automatically exclude it.
I updated the TSQL. STRING_AGG concatenates the string with each database. Without it it only returns the last database. STRING_AGG is more secure than += which also concatenates. I changed the code so it generates and executes the query. In SQL 2019 the query is all in one line using +=. I don't have SQL 2016. It may format it better in SQL 2016. You can uncomment --SELECT #SQL3 to see what the query looks like. Please mark as answer if this is what you need.
DECLARE #TblName TABLE
(
TblName VARCHAR(100)
)
Declare #SQL VARCHAR(MAX),
#SQL3 VARCHAR(MAX),
#DBName VARCHAR(50),
#Count Int,
#LoopCount Int
Declare #SQL2 VARCHAR(MAX) = ''
Select Identity(int,1,1) ID, name AS DBName into #Temp from sys.databases
Select #Count = ##RowCount
Set #LoopCount = 1
While #LoopCount <= #Count
Begin
SET #DBName = (SELECT DBName FROM #Temp Where ID = #LoopCount)
SET #SQL =
' USE ' + #DBName +
' SELECT TABLE_CATALOG FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = ''table'''
INSERT INTO #TblName (TblName)
EXEC (#SQL)
Set #LoopCount=#LoopCount + 1
End
SELECT #SQL2 +=
' SELECT ' + char(10) + 
' [col1] ' + char(10) + 
' ,[col2] ' + char(10) + 
' ,[col3] ' + char(10) + 
' FROM [' + TblName + '].[dbo].[table] ' + char(10) + 
' UNION '
FROM #TblName
DROP TABLE #Temp
SET #SQL3 = (SELECT SUBSTRING(#SQL2, 1, LEN(#SQL2) - 5))
--SELECT #SQL3
EXEC (#SQL3)

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.

Dropping and recreating databases in Microsoft 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

Renaming multiple tables

In SQL Server, I have a database abc. In this database I have hundreds of tables. Each of these tables is called xyz.table
I want to change all the tables to be called abc.table.
Do we have a way by which I can change all the names from xyz.table to abc.table in database abc?
I am able to manually change the name by changing the schema for each table to abc
You could have a cursor run over all your tables in the xyz schema and move all of those into the abc schema:
DECLARE TableCursor CURSOR FAST_FORWARD
FOR
-- get the table names for all tables in the 'xyz' schema
SELECT t.Name
FROM sys.tables t
WHERE schema_id = SCHEMA_ID('xyz')
DECLARE #TableName sysname
OPEN TableCursor
FETCH NEXT FROM TableCursor INTO #TableName
-- iterate over all tables found
WHILE ##FETCH_STATUS = 0
BEGIN
DECLARE #Stmt NVARCHAR(999)
-- construct T-SQL statement to move table to 'abc' schema
SET #Stmt = 'ALTER SCHEMA abc TRANSFER xyz.' + #TableName
EXEC (#Stmt)
FETCH NEXT FROM TableCursor INTO #TableName
END
CLOSE TableCursor
DEALLOCATE TableCursor
You can use Alter Schema with an undocumented Stored Procedure exec sp_MSforeachtable which basically iterates through all the tables .
exec sp_MSforeachtable "ALTER SCHEMA new_schema TRANSFER ? PRINT '? modified' "
change the new_schema keyword with your new Schema .
For details please go through the link
sp_MSforeachtable
Alter Schema for all the tables
As others have pointed out that the SP is deprecated so There is another way to do this by getting the names of the table from sys.tables
Declare #value int
Set #value=1
declare #sql varchar(max), #table varchar(50), #old varchar(50), #new varchar(50)
set #old = 'dbo'
set #new = 'abc'
while exists(select * from sys.tables where schema_name(schema_id) = #old)
begin
;With CTE as
(
Select *,row_number() over(order by object_id) rowNumber from sys.tables
where schema_name(schema_id) = #old
)
select #table= name from CTE where #value=rowNumber
Set #value=#value+1
set #sql = 'alter schema ' + #new + ' transfer ' + #old + '.' + #table
exec(#sql)
end
I'm assuming You've already created the schema abc in the database.
If not you can refer here
http://www.youtube.com/watch?v=_DDgv8uek6M
http://www.quackit.com/sql_server/sql_server_2008/tutorial/sql_server_database_schemas.cfm
To change the schema of all the tables in database you can use following system created msforeachtable stored procedure to rename schema of each table with alter schema.
exec sp_MSforeachtable "ALTER SCHEMA abc TRANSFER ? PRINT '? modified' "
Without using the undocumented/unsupported sp_MSforeachtable procedure, here's a somewhat concise way to select and/or run all of the necessary ALTER statements for every table on the given schema:
declare #oldSchema nvarchar(50) = 'abc' -- usually 'dbo'
declare #newSchema nvarchar(50) = 'xyz' -- use your new schema name
declare #sql nvarchar(max) =
(select
(select N'alter schema [' + #newSchema + '] transfer [' + #oldSchema + '].[' + name + ']
' as 'data()'
from sys.tables
where schema_name(schema_id) = #oldSchema for xml path(''), type)
.value('text()[1]','nvarchar(max)'))
-- You can select out the results for scrutiny
select #sql
-- Or you can execute the results directly
exec (#sql)
This avoids using a cursor, and uses brackets to escape table names that may conflict with SQL keywords.

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