Drop multiple databases in SQl Azure - sql

I would like to run a script to drop the multiple databases from SQL Azure as soon I finish using it. When I tried as following,
DECLARE #dbname varchar(100);
DECLARE #stmt nvarchar(3000);
SET #dbname = '6A732E0B';
SELECT #stmt = (SELECT 'DROP DATABASE [' + name + ']; ' FROM sys.databases
WHERE name LIKE '%' +#dbname +'%');
EXEC sp_executesql #stmt;
SQL Azure throws error message as “The DROP DATABASE statement must be the only statement in the batch”
Can somebody help me on this?

This is a known limitation in SQL Azure - certain statements need to be in a batch by themselves to be executed. This includes CREATE/ALTER DATABASE, ALTER DATABASE and a few more.
To solve you problem, you can create a loop in you application where you iterate over all the databases and drop them by issuing DROP DATABASE statements in separate batches.

I believe this is a bug of SQL Azure. I've recently reported it to Microsoft:
https://connect.microsoft.com/SQLServer/feedback/details/684160/sp-executesql-the-drop-database-statement-must-be-the-only-statement-in-the-batch

Related

Indexing same table in multiple databases

I have almost 150 databases with all the same tables. I know its bad but I don't have control over it. I'm trying to improve performance with some indexes. I know what the indexes should be but I need to build them on the same tables in every database. Is there a way to do this bsides creating them all separately?
I had a similar situation a while back so I came up with this code. You can use dynamic SQL with sp_MSforeachdb to loop through your databases. I've excluded the system databases below but you can include/exclude databases as you like in that first IF.
This code will check each database for your specific table as well as checking to see if that index already exists on that table. If not, it creates it. I included a RAISERROR to show the progress through the databases in SSMS messages. Just change the table/index names below and update the CREATE INDEX statement as appropriate for you.
DECLARE #command varchar(1000)
SELECT #command = 'IF ''?'' NOT IN(''master'', ''model'', ''msdb'', ''tempdb'')
BEGIN USE ?
EXEC(''
DECLARE #DB VARCHAR(200)
SET #DB = DB_NAME()
RAISERROR (#DB, 10, 1) WITH NOWAIT
IF OBJECT_ID(''''dbo.TableName'''', ''''U'''') IS NOT NULL
BEGIN
IF NOT EXISTS (SELECT 1 FROM sys.indexes WHERE name=''''IX_TableName'''' AND object_id = OBJECT_ID(''''TableName''''))
BEGIN
CREATE INDEX [IX_TableName] ON TableName (indexColumn)
END
END
'') END'
EXEC sp_MSforeachdb #command

Bypassing character limit on OPENQUERY failing use EXECUTE

I am currently using SQL Server Management Studio 17 to connect to an Oracle database instance and then extract some data and insert it into a SQL Server Table I have.
I have tried doing the following:
DROP TABLE IF EXISTS [jerry].[dbo].[purchases]
SELECT * INTO [jerry].[dbo].[purchases] FROM OPENQUERY(OLAP, '
proprietary sql code
');
However the SQL code is about 9500 characters and thus OPENQUERY fails, which is supported by MSDN articles
I referenced these sites:
- MSDN One - MSDN Two
and learned that I can use EXEC to accomplish my goal.
I have tried to implement the following:
EXEC master.dbo.sp_serveroption #server=N'OLAP', #optname=N'rpc out', #optvalue=N'true'
DECLARE #sqlcode VARCHAR(MAX)
SET #sqlcode = 'sql code'
DROP TABLE IF EXISTS [jerry].[dbo].[purchases]
EXEC #sqlcode AT OLAP
However, I am still getting an Invalid Syntax near OLAP error.
I have confirmed that OLAP is the correct name from our DBA and other OPENQUERY functions work just fine (with much shorter SQL statements).
I cannot edit the SQL query
I cannot edit the external OLAP's databases permissions (I am not the DBA nor am I in the security group)
Any assistance is greatly appreciated.
EXEC without parentheses runs a stored procedure.
So try:
truncate table [jerry].[dbo].[purchases]
insert into [jerry].[dbo].[purchases]
exec ( #sqlcode ) at olap
See execute

How to use 'use' command across all database to execute certain script in sql

I have a certain script which I need to execute across all databases in SQL Server. I have used the following logic to loop through all database excluding the system databases.
declare #DBName varchar(500)
DECLARE #Database_id int
DECLARE #Query varchar(MAX)
select #Database_id = MIN(database_id) from sys.databases where database_id>4
while #Database_id is not null
begin
select #DBName=name from sys.databases where database_id=#Database_id
set #Query = 'Use'+#DBName
--some script
Print ''+#DBName+''
exec (#Query)
select #Database_id = MIN(database_id) from sys.databases where database_id>4 AND database_id>#Database_id
end
But the problem is I can't use the 'Use' command with a variable. Is there any other way to make use of 'Use' command to hit the database?
And I don't want to use sp_MSforeachdb command as my query is too long.
Any help would be appreciated!
There is an undocumented function doing this. You can use the question mark in the place of the db's name:
EXECUTE master.sys.sp_MSforeachdb 'USE [?]; EXEC sp_spaceused'
Find this example and more explanations here: http://weblogs.sqlteam.com/joew/archive/2008/08/27/60700.aspx
EDIT: From your comments above I find, that you do not want to includ the system dbs into your run. It seems to be q bit tricky to detect, whether a db is a system db or not but you could go like this:
DECLARE #cmd VARCHAR(1000)='USE [?];IF DB_ID(DB_NAME())<=4 RETURN;EXEC sp_spaceused;'
EXECUTE master.sys.sp_MSforeachdb #cmd;
GO
Read about the flaws here (about SQL Server 2005!): SQL Server: How to tell if a database is a system database?
If you don't like this <=4 you could simply do it like
IF DB_NAME() IN('master','model',... any more names here ... ) RETURN;
The only real restriction I know of is, that sp_MSforeachdb does not like "GO".

SQL Server: How to get and use name of the database in SP

I'm working on two different servers with the same structure, one of them is where we develope, and the other one is the live server. My main database (let's call it MainDB) has the same name in both databases, but the others (call those DBi in live server and DB_i in developement server) do not. I have some syncronization stored procedures which transfer data from the databases DBi to MainDB. In the developement server, I use different names then the live server, then after every change in the sync procedures of developement server, I have to change the names of the databases before transfering them to live server.
Now, my aim is to write functions which would return the names of the databases. However, I have no idea what type of data to return in order to use the return value as the name of the database.
For instance, assume I have a query like:
SELECT * FROM DB1.dbo.Table1
in live server. In the developement server, it's:
SELECT * FROM DB_1.dbo.Table1
And my aim is to be able to define something like:
DECLARE #DBName1 [SOME_TYPE]= GetDBName(#DBID_1)
and then use it as:
SELECT * FROM #DBName1.dbo.Table1
It doesn't have to be exactly like this of course, but the functionality must be the same. You may ask why would I need something like that. I don't wanna change the code before all the transfers. I wanna use the same sp in both servers, but get different names for databases from the functions, as I would only change the return value of the functions in servers for only one time.
CREATE PROCEDURE usp_SomeProc
#DB_Name NVARCHAR(128)
AS
BEGIN
SET NOCOUNT ON;
DECLARE #Sql NVARCHAR(MAX);
SET #Sql = N'SELECT * FROM ' + QUOTENAME(#DBName1) + N'.[dbo].[Table1] '
EXECUTE sp_executesql #Sql
END
Edit
DECLARE #Query NVARCHAR(MAX);
DECLARE #DBName nvarchar(50) = 'DBName'
SET #Query = N'SELECT * FROM ' + QUOTENAME(#DBName) + N'.dbo.Table'
EXECUTE sp_executesql #Query

Drop all objects in SQL Server database that belong to different schemas?

Is there a way to drop all objects in a db, with the objects belonging to two different schemas?
I had been previously working with one schema, so I query all objects using:
Select * From sysobjects Where type=...
then dropped everything I using
Drop Table ...
Now that I have introduced another schema, every time I try to drop it says something about I don't have permission or the object does not exist. BUT, if I prefix the object with the [schema.object] it works. I don't know how to automate this, cause I don't know what objects, or which of the two schemas the object will belong to. Anyone know how to drop all objects inside a db, regardless of which schema it belongs to?
(The user used is owner of both schemas, the objects in the DB were created by said user, as well as the user who is removing the objects - which works if the prefix I used IE. Drop Table Schema1.blah)
Use sys.objects in combination with OBJECT_SCHEMA_NAME to build your DROP TABLE statements, review, then copy/paste to execute:
SELECT 'DROP TABLE ' +
QUOTENAME(OBJECT_SCHEMA_NAME(object_id)) + '.' +
QUOTENAME(name) + ';'
FROM sys.objects
WHERE type_desc = 'USER_TABLE';
Or use sys.tables to avoid need of the type_desc filter:
SELECT 'DROP TABLE ' +
QUOTENAME(OBJECT_SCHEMA_NAME(object_id)) + '.' +
QUOTENAME(name) + ';'
FROM sys.tables;
SQL Fiddle
Neither of the other questions seem to have tried to address the all objects part of the question.
I'm amazed you have to roll your own with this - I expected there to be a drop schema blah cascade. Surely every single person who sets up a dev server will have to do this and having to do some meta-programming before being able to do normal programming is seriously horrible. Anyway... rant over!
I started looking at some of these articles as a way to do it by clearing out a schema: There's an old article about doing this, however the tables mentioned on there are now marked as deprecated. I've also looked at the documentation for the new tables to help understand what is going on here.
There's another answer and a great dynamic sql resource it links to.
After looking at all this stuff for a while it just all seemed a bit too messy.
I think the better option is to go for
ALTER DATABASE 'blah' SET SINGLE_USER WITH ROLLBACK IMMEDIATE
drop database 'blah'
create database 'blah'
instead. The extra incantation at the top is basically to force drop the database as mentioned here
It feels a bit wrong but the amount of complexity involved in writing the drop script is a good reason to avoid it I think.
If there seem to be problems with dropping the database I might revisit some of the links and post another answer
try this with sql2012 or above,
this script may help to delete all objects by selected schema
Note: below script for dbo schema for all objects but you may change in very first line #MySchemaName
DECLARE #MySchemaName VARCHAR(50)='dbo', #sql VARCHAR(MAX)='';
DECLARE #SchemaName VARCHAR(255), #ObjectName VARCHAR(255), #ObjectType VARCHAR(255), #ObjectDesc VARCHAR(255), #Category INT;
DECLARE cur CURSOR FOR
SELECT (s.name)SchemaName, (o.name)ObjectName, (o.type)ObjectType,(o.type_desc)ObjectDesc,(so.category)Category
FROM sys.objects o
INNER JOIN sys.schemas s ON o.schema_id = s.schema_id
INNER JOIN sysobjects so ON so.name=o.name
WHERE s.name = #MySchemaName
AND so.category=0
AND o.type IN ('P','PC','U','V','FN','IF','TF','FS','FT','PK','TT')
OPEN cur
FETCH NEXT FROM cur INTO #SchemaName,#ObjectName,#ObjectType,#ObjectDesc,#Category
SET #sql='';
WHILE ##FETCH_STATUS = 0 BEGIN
IF #ObjectType IN('FN', 'IF', 'TF', 'FS', 'FT') SET #sql=#sql+'Drop Function '+#MySchemaName+'.'+#ObjectName+CHAR(13)
IF #ObjectType IN('V') SET #sql=#sql+'Drop View '+#MySchemaName+'.'+#ObjectName+CHAR(13)
IF #ObjectType IN('P') SET #sql=#sql+'Drop Procedure '+#MySchemaName+'.'+#ObjectName+CHAR(13)
IF #ObjectType IN('U') SET #sql=#sql+'Drop Table '+#MySchemaName+'.'+#ObjectName+CHAR(13)
--PRINT #ObjectName + ' | ' + #ObjectType
FETCH NEXT FROM cur INTO #SchemaName,#ObjectName,#ObjectType,#ObjectDesc,#Category
END
CLOSE cur;
DEALLOCATE cur;
SET #sql=#sql+CASE WHEN LEN(#sql)>0 THEN 'Drop Schema '+#MySchemaName+CHAR(13) ELSE '' END
PRINT #sql
EXECUTE (#sql)
I do not know wich version of Sql Server are you using, but assuming that is 2008 or later, maybe the following command will be very useful (check that you can drop ALL TABLES in one simple line):
sp_MSforeachtable "USE DATABASE_NAME DROP TABLE ?"
This script will execute DROP TABLE .... for all tables from database DATABASE_NAME. Is very simple and works perfectly. This command can be used for execute other sql instructions, for example:
sp_MSforeachtable "USE DATABASE_NAME SELECT * FROM ?"