MS SQL Database Table Prefix from Previous Owner - sql-server

I have an MS SQL 2000 database that was backed up from a public server and restored at a test location for an upgrade test. The problem is that the user that had access permission on the public server does not exist on the testing server, and now all tables are prefixed with that username (which requires ALL queries against those tables to be changed!)
Is there any quick way to fix this? I have changed the database owner but this did not help.

Create the login and users, but find out the SID from sysusers
EXEC sp_addlogin 'TheLogin', 'ThePassword', #sid = ???
EXEC sp_adduser 'TheLogin','TheUser'
Note: SQL Server 2000 so can't use CREATE LOGIN or CREATE USER

Ok, found the answer - the OBJECT owner must be changed to DBO, negating the need to prefix references to your object in your SQL scripts/queries - the object in this case being the database table(s)
Here is a script that will change the owner for objects within a database (not my own code)
DECLARE #currentObject nvarchar(517)
DECLARE #qualifiedObject nvarchar(517)
DECLARE #currentOwner varchar(50)
DECLARE #newOwner varchar(50)
SET #currentOwner = 'old_owner'
SET #newOwner = 'dbo'
DECLARE alterOwnerCursor CURSOR FOR
SELECT [name] FROM dbo.sysobjects
WHERE xtype = 'U' or xtype = 'P'
AND LEFT([name], 2) <> 'dt'
OPEN alterOwnerCursor
FETCH NEXT FROM alterOwnerCursor INTO #currentObject
WHILE ##FETCH_STATUS = 0
BEGIN
SET #qualifiedObject = CAST(#currentOwner as varchar) + '.' + CAST(#currentObject as varchar)
EXEC sp_changeobjectowner #qualifiedObject, #newOwner
FETCH NEXT FROM alterOwnerCursor INTO #currentObject
END
CLOSE alterOwnerCursor
DEALLOCATE alterOwnerCursor

Related

Get the database name in which Stored Procedure exists

I am having SQL server 2008 and i am having 10 different databases in it and now i want to search one stored procedure that in which database the stored procedure is present.
Mentioned as duplicate by some ..... with out reading my question properly. My Requirement is i need to verify 'SP_Email' procedure. I which database is this procedure exists.
You can try this:
EXEC sp_msforeachdb
'if exists(select 1 from [?].sys.objects where name=''SP_Email'')
select ''?'' as FoundInDatabase from [?].sys.objects where name=''SP_Email'''
Please try this.
SELECT name DatabaseName
FROM sys.databases
WHERE OBJECT_ID(QUOTENAME(name) + '.dbo.ProcedureNameHere', 'P') IS NOT NULL;
This will return the database(s) name in which this particular object exist.
Replace ProcedureNameHere with your procedure name. In your case it would be SP_Email Keep rest of the things as it is.
you need to query sys.databases of master database to get list of databases and for each database name you get you need to query the db_name.sys.procedures to check if it exists.
try below query and give a feedback:
use master
go
declare #FullQuery varchar(max)
declare #DBName varchar(50)
set #FullQuery=''
declare cr cursor for select name from sys.databases where database_id > 4
open cr
fetch next from cr into #DBName
while(##fetch_status=0)
begin
set #FullQuery=#FullQuery+
' select name COLLATE SQL_Latin1_General_CP1_CI_AS from '+#DBName+'.sys.procedures where name like ''%proc_name%'' union'
fetch next from cr into #DBName
end
close cr
deallocate cr
set #FullQuery=substring(#FullQuery,1,len(#FullQuery)-5)
exec (#FullQuery)
SELECT OBJECT_ID('DataBase1.SchemaName.StoredProcedureName') /
OBJECT_ID('DataBase2.SchemaName.StoredProcedureName') /
OBJECT_ID('DataBase3.SchemaName.StoredProcedureName') /
...
It will return NULL if there is no such procedure. This will work if all databases are on same instance.

Scope of ## variable in TSQL

In the following TSQL code I can use my local variable in first few lines and then I cannot use it again. Why am I not able to use it in the last line of my code ?
Where does its scope end?
DECLARE ##CurrentDB varchar(50);
SET ##CurrentDB = 'MyDBNAME';
-- Find Data & Log Fiel locations
SELECT DB_NAME(database_id) AS DatabaseName, name AS LogicalFileName, physical_name AS PhysicalFileName, size/(128*1024) [GB]
FROM sys.master_files AS mf
WHERE DB_NAME(database_id) = ##CurrentDB
-- Detach DB
USE
GO
ALTER DATABASE SET SINGLE_USER WITH ROLLBACK IMMEDIATE
GO
USE [master]
GO
EXEC master.dbo.sp_detach_db #dbname = ##Cur
GO
Here is the error:
Any time you pass SQL Server a GO command, that ends the context in which the variable exists and it is no longer accessible by anything after that point in the T-SQL code. "Global" variables as such do not exist in SQL Server, but there are ways around it, generally by implementing a global variable table (either temporary or permanent).
You can get the general idea from this blog post that sets up a permanent table to track global variables.
As a workaround, you can use a Global Temp Table:
Declare #CurrentDB varchar(50)
SET #CurrentDB = 'MyDBNAME'
Create Table ##CurrentDB (Name varchar(50))
Insert Into ##CurrentDB Values (#CurrentDB)
GO
-- ...
GO
Declare #CurrentDB varchar(50)
Select Top 1 #CurrentDB = Name From ##CurrentDB
Select #CurrentDB
This should work even if you are using different databases in each part of your script.
Why use a global variable or temp table at all? This cries out to me to be a user defined stored procedure.
Here are the business rules.
1 - You basically want to get the location and size of a database you want to detach.
2 - Want to set database to single user mode.
3 - You want to detach the database. Just remember the files will be hanging around afterwards.
I created it in the MSDB database but you can put it in your own toolbox database.
I did not check to see if the database is really in use only mode. - TODO list
Just check the mode in the sys.databases table. If the ALTER, fails do not try the detach. Just notify the user to find the spids and kill them.
http://technet.microsoft.com/en-us/library/ms178534.aspx
4 - I did not put any error handling in. - TODO list
Last but not least, this solution could be prone to SQL injection, do not give the world access.
In short, the stored procedure below does just what you want.
--
-- Create a user stored procedure
--
-- Start in msdb
use msdb
go
-- drop existing
if object_id('my_detach_process') > 0
drop procedure my_detach_process
go
-- create new
create procedure my_detach_process(#dbname sysname)
as
-- Show the data
SELECT
DB_NAME(mf.database_id) AS DatabaseName,
mf.name AS LogicalName,
mf.physical_name AS PhysicalName, mf.size as SizeMb
FROM sys.master_files AS mf
WHERE DB_NAME(database_id) = #dbname;
-- Set to single user
DECLARE #sqlstmt1 nvarchar(512) = '';
SET #sqlstmt1 = 'ALTER DATABASE [' + #dbname + '] SET SINGLE_USER WITH ROLLBACK IMMEDIATE';
EXEC sp_executesql #sqlstmt1;
-- Detach
DECLARE #sqlstmt2 nvarchar(512) = '';
SET #sqlstmt2 = 'USE [master]; EXEC master.dbo.sp_detach_db #dbname = ' + #dbname;
EXEC sp_executesql #sqlstmt2;
GO
--
-- Sample call
--
-- Choose master
use master
go
-- Create toy db
create database toy;
go
-- Call the sp
exec msdb.dbo.my_detach_process #dbname = 'Toy'
Sample output from sample call.

Azure SQL Database Create via bacpac Import Fails

We are testing the migration from a local SQL Server 2008R2 database to Azure, but have hit a bump in the road.
Process followed, based on SO articles:
Installed SQL Server 2012 Client tools
Amended DB to remove indexes with a fill factor specified, as well as invalid views and procedures (this was determined by using the Export Data-tier Application tool for SSMS, until it successfully created bacpac file)
uploaded the successfully created bacpac file to Azure
Went through steps to create new database using import method
bacpac file is retrieved from blob storage status shown, but then the following error occurs
BadRequest ;Request Error;Error Status Code:</B>
'BadRequest'</P><P><B>Details:
</B>Error encountered during the service operation. ; Exception
Microsoft.SqlServer.Management.Dac.Services.ServiceException:Unable to
authenticate request; </P></DIV></BODY></html>
Note: error text above was trimmed to exclude URL's as I don't have sufficient points.
I can't seem to find any info on this error or where there may be any additional log details to help determine why it will not import.
As the error mentions unable to authenticate, we also tried doing the following:
Created a new user and password on the local DB
Used this same new user and password for the definition of the new DB on Azure
This did not make any difference.
Would appreciate if someone could point us in the right direction to get this working, as we would need to replicate this process quite a few times.
Thanks.
We needed the same thing. Here is some steps that we did and the results:
1) Exporting using SQL Database Migration Tool created by ghuey
You can download here: https://sqlazuremw.codeplex.com/
It's a great tool and i really recommend you to try this first. Depends of the complexity of your database, it will work just fine.
For us, unfortunately didnt work. So you moved to the next step.
2) DAC Package
The 2008 has the option to generate the DACPAC witch creates the structure of the database on Azure and then you can Deploy to Azure by references a connection in the 2008 Studio Managament, Right click on Azure Server, Deploy ... se more details here: http://world.episerver.com/documentation/Items/Upgrading/EPiserver-Commerce/8/Migrating-Commerce-databases-to-Azure/
Well, if this works for you, TRY THIS. It's more easy.
For us, unfortunately didnt work. So you moved to the next step.
3) Using an 2012 server to export bacpac and then import into azure
This steps requires multiple actions to complete. Here it is:
a. Generate a backup into 2008 and move the file do 2012 server;
b. Restore the backup into 2012;
c. Do some SQL that:
c1. Set all owners of SCHEMAs to DBO. You can use an SQL to move schema like this: ALTER AUTHORIZATION ON SCHEMA::[db_datareader] TO [dbo]
c2. Remove all users that was created by you;
c3. Remove all MS_Description (Extend Properties) of all columns and tables
c4. Drop all constraints (tip: generate a complete script of the database with drop and create option enabled and copy the part of "drop constraint"
c5. We need to removed the fill factor options of the indexes of your database. You can do that re-creating the index (including PK that has clustered index associated). Well to drop every PK Clustered, is not that easy but with a little help of Google you will able do find an script to help you create and drop. Here is the script:
DECLARE #object_id int;
DECLARE #parent_object_id int;
DECLARE #TSQL NVARCHAR( 4000);
DECLARE #COLUMN_NAME SYSNAME;
DECLARE #is_descending_key bit;
DECLARE #col1 BIT;
DECLARE #action CHAR( 6);
SET #action = 'DROP';
--SET #action = 'CREATE';
DECLARE PKcursor CURSOR FOR
select kc.object_id , kc .parent_object_id
from sys.key_constraints kc
inner join sys .objects o
on kc.parent_object_id = o.object_id
where kc.type = 'PK' and o. type = 'U'
and o.name not in ( 'dtproperties','sysdiagrams' ) -- not true user tables
order by QUOTENAME (OBJECT_SCHEMA_NAME( kc.parent_object_id ))
,QUOTENAME( OBJECT_NAME(kc .parent_object_id));
OPEN PKcursor ;
FETCH NEXT FROM PKcursor INTO #object_id, #parent_object_id;
WHILE ##FETCH_STATUS = 0
BEGIN
IF #action = 'DROP'
SET #TSQL = 'ALTER TABLE '
+ QUOTENAME (OBJECT_SCHEMA_NAME( #parent_object_id))
+ '.' + QUOTENAME(OBJECT_NAME (#parent_object_id))
+ ' DROP CONSTRAINT ' + QUOTENAME(OBJECT_NAME (#object_id))
ELSE
BEGIN
SET #TSQL = 'ALTER TABLE '
+ QUOTENAME (OBJECT_SCHEMA_NAME( #parent_object_id))
+ '.' + QUOTENAME(OBJECT_NAME (#parent_object_id))
+ ' ADD CONSTRAINT ' + QUOTENAME(OBJECT_NAME (#object_id))
+ ' PRIMARY KEY'
+ CASE INDEXPROPERTY( #parent_object_id
,OBJECT_NAME( #object_id),'IsClustered' )
WHEN 1 THEN ' CLUSTERED'
ELSE ' NONCLUSTERED'
END
+ ' (' ;
DECLARE ColumnCursor CURSOR FOR
select COL_NAME (#parent_object_id, ic.column_id ), ic .is_descending_key
from sys .indexes i
inner join sys. index_columns ic
on i .object_id = ic .object_id and i .index_id = ic .index_id
where i .object_id = #parent_object_id
and i .name = OBJECT_NAME (#object_id)
order by ic. key_ordinal;
OPEN ColumnCursor ;
SET #col1 = 1 ;
FETCH NEXT FROM ColumnCursor INTO #COLUMN_NAME, #is_descending_key;
WHILE ##FETCH_STATUS = 0
BEGIN
IF (#col1 = 1 )
SET #col1 = 0
ELSE
SET #TSQL = #TSQL + ',';
SET #TSQL = #TSQL + QUOTENAME( #COLUMN_NAME)
+ ' '
+ CASE #is_descending_key
WHEN 0 THEN 'ASC'
ELSE 'DESC'
END;
FETCH NEXT FROM ColumnCursor INTO #COLUMN_NAME, #is_descending_key;
END;
CLOSE ColumnCursor ;
DEALLOCATE ColumnCursor ;
SET #TSQL = #TSQL + ');';
END;
PRINT #TSQL;
FETCH NEXT FROM PKcursor INTO #object_id , #parent_object_id ;
END;
CLOSE PKcursor ;
DEALLOCATE PKcursor ;
c6. Re-create the FKs
c7. Remove all indexes
c8. Re-create all indexes (without the fill factor options)
d. Now, right click on the database on 2012 and export data-tier to Azure Storage in format BACPAC. After finished, import on Azure.
It should works :-)
For anyone who may stumble across this, we have been able to locate the issue by using the bacpac file to create a new database on the local 2008R2 server, through the 2012 Client tools.
The error relates to a delete trigger that is being fired, which I don't understand why it is being executed, but that's another question.
Hopefully this may help others with import errors on SQL Azure.

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

How to find out whether sql server login has any user mapped to using SMO

I need to write a function to delete the login in the database if it does not have any users to map to using SQL Server Management Objects (SMO). How can I achieve this ?
Just like to add that when using the login.EnumDatabaseMappings(),when there are no users mappped to the login , will return null.So you can not use something like login.EnumDatabaseMappings().Length rather you should use
mylogin = server.Logins(loginName)
If Not mylogin Is Nothing Then
If Not mylogin.EnumDatabaseMappings() Is Nothing Then
mylogin.Drop()
End If
End If
How about this:
Server server = new Server("your server name");
foreach (Login login in server.Logins)
{
DatabaseMapping[] mappings = login.EnumDatabaseMappings();
}
Should work and give you what you're looking for.
Give this a go,
If you comment out the code about the cursor and look at the result of the select statement you can see what logins it wants to drop.
USE MASTER;
GO
DECLARE #loginName varchar(max)
DECLARE #SQL varchar(max)
CREATE TABLE #dbusers (
sid VARBINARY(85))
EXEC sp_MSforeachdb
'insert #dbusers select sid from [?].sys.database_principals where type != ''R'''
DECLARE loginCursor CURSOR FOR
SELECT name
FROM sys.server_principals
WHERE sid IN (SELECT sid
FROM sys.server_principals
WHERE TYPE != 'R'
AND name NOT LIKE ('##%##')
EXCEPT
SELECT DISTINCT sid
FROM #dbusers)
AND type_desc = 'SQL_LOGIN'
OPEN loginCursor
FETCH NEXT FROM loginCursor into #loginName
WHILE ##FETCH_STATUS=0
BEGIN
SET #SQL = 'DROP LOGIN '+#loginName
EXEC sp_executesql #SQL
END
CLOSE loginCursor
DEALLOCATE loginCursor
GO
DROP TABLE #dbusers

Resources