Make SQL Server generate SQL for you using SELECT literals
Suppose that I've got an instance of SQL server setup for testing, and I've programmatically created databases on this instance, but never cleaned them up.
This can leave you with hundreds of databases that you'll never use again, and there's no reason for them to continue taking up space and cluttering things which you do not wish to be cluttered.
Now, you could use a GUI tool like enterprise manager, and right click on every database and choose "Delete"
Obviously, that stinks.
Alternatively, you could use isqlw (SQL Query Analyzer) and enter the appropriate T-SQL statement to delete a database:
drop database Foo
go
This also stinks, because thats a lot of typing, once you do it for 100 databases
Fortuneately, you can do better. What you've got, fundamentally, is a problem that computers are good at. You've got a lot of somethings (databases) that you want to do something to. You know what you want to do - drop a database. Now you just need to leverage that across a big list of them.
If one wanted to get a list of data in SQL, one would write a a SELECT statement. It turns out that if we're willing to look at the system tables, sql server will tell us about the databases installed in this instance.
select name
from sysdatabases
where sid <> 0x01
and name like 'HW_%'
Now, this will give you the name of any databases from this instance which match "HW_%" and which have an sid other than 0x01. The sid <> 0x01 clause is interesting. On the SQL instances I'm looking at, the "system" databases always have sid=0x01. But on one other instance, Northwind also has sid=0x01. User databases always have a long gooofy, non-0x01 value for sid. So you can use this as a hack to do a "reasonable" job of excluding "system" databases from your select list. If you can make a determination based on the dbname, as I have above, you can do even better.
Great, we can get SQL server to tell us the list of user databases installed from this instance. What does that buy me? Well, suppose we change the select list:
select 'drop database ', name
from sysdatabases
where sid <> 0x01
and name like 'HW_%'
If you run this select statement (and you have databases that match the select list) you'll get the following output (at least on my machine - you probably won't get this output as your dbnames will be different
drop database HW_North
drop database HW_South
drop database HW_Enterprise
Congratulations, you've just told SQL server to generate SQL for you. Obviously, if you had 100 databases in your select list, you'd get 100 statements generated. Here's where the hack comes in, i don't know of a way to actually execute this in one step, but I bet it is possible. Instead, I copy and paste the results (results to grid works fine in ISQLW, results as text will give you a giant column width for the name column), back into a command window, and then execute the batch.
This technique is handy for dropping lots of databases, but its also good in other places. For instance, you can generate INSERT or UPDATE statements this way, which may be desirable if you've got just one or two peices that make doing the job with a single insert/update too difficult.
It is not elegant, not efficient, and probably upsets somebody somewhere, but for a quick and dirty management task, using select literals to generate statements for you is a great technique to keep in mind.
Comments
- Anonymous
November 23, 2004
Look at sp_execresultset. It's undocumented but it works. - Anonymous
November 23, 2004
Here's two different ways to go about complete automation, they're techniques we use almost every day here on our hundreds of databases:
-- BEGIN SQL BLOCK 1 --
USE master
GO
DECLARE @dbname sysname
DECLARE @SQL nvarchar(1000)
DECLARE cur CURSOR FORWARD_ONLY KEYSET FOR
SELECT name FROM sysdatabases WHERE name like 'sc_%' escape ''
OPEN cur
FETCH NEXT FROM cur INTO @dbname
WHILE @@FETCH_STATUS = 0
BEGIN
SET @SQL = N'DROP DATABASE ' + @dbname
exec sp_executesql @SQL
FETCH NEXT FROM cur INTO @dbname
END
CLOSE cur
DEALLOCATE cur
-- END SQL BLOCK 1 --
Or there's an undocumented system stored proc in SQL Server 2000 that may or may not be there in future releases:
-- BEGIN SQL BLOCK 2 --
exec sp_msforeachdb 'if CHARINDEX(''SC_'',''?'') = 1 DROP DATABASE ?'
-- END SQL BLOCK 2 -- - Anonymous
November 23, 2004
The comment has been removed - Anonymous
November 24, 2004
The comment has been removed