Problem
Have you ever had to attach databases on a SQL Server? This could be done using the SQL Server Management Studio (SSMS) GUI which is great if it is a one time need, but if you have many databases this could take time. The other option is to write T-SQL code to do the attach, but this also takes time to write for each database. Or have you ever run into the situation where you have detached databases that need to be attached to a new server or an existing server? In this tip I share a way to do this job fast without the need to have to do this manually or write T-SQL code.
Solution
DBCC CHECKPRIMARYFILE is one of the many undocumented SQL Server commands that we can use to do our job as DBAs. Because it is an “undocumented command” we should use caution, but fortunately this is not a dangerous command. This command is used only for reading meta data from the primary database data file on disk and to return information that is very useful, such as the database name, logical names, physical file names and more without having to attach it to an instance of SQL Server.
First of all, I will show the syntax and how to use DBCC CHECKPRIMARYFILE.
Syntax:DBCC CHECKPRIMARYFILE ({'PhysicalFileName'} [,opt={0|1|2|3}])
PhysicalFileName is the full path for the primary database file.
opt=0 - checks if the file a primary database file.
opt=1 - returns name, size, maxsize, status and path of all files associated to the database.
opt=2 - returns the database name, version and collation.
opt=3 - returns name, status and path of all files associated with the database.
SQL Server DBCC CHECKPRIMARYFILE with Option = 0
First we will use it with zero to check if it is the primary file, if so it will return 1 otherwise 0.
DBCC CHECKPRIMARYFILE('D:\SQLData\AdventureWorksDW2012_Data.mdf',0) WITH NO_INFOMSGS
Note that the option 0 is the default value, so you don’t need to use a value if you only want to check if it is the primary file or not.
DBCC CHECKPRIMARYFILE('D:\SQLData\AdventureWorksDW2012_Data.mdf') WITH NO_INFOMSGSDBCC CHECKPRIMARYFILE with Option = 1
To check logical name, size, maxsize, status and physical name of all files we use option 1.
DBCC CHECKPRIMARYFILE('D:\SQLData\AdventureWorksDW2012_Data.mdf',1) WITH NO_INFOMSGS
DBCC CHECKPRIMARYFILE with Option = 2
Checks the database name, version and collation.
DBCC CHECKPRIMARYFILE('D:\SQLData\AdventureWorksDW2012_Data.mdf',2) WITH NO_INFOMSGS
DBCC CHECKPRIMARYFILE with Option = 3
Checks the logical name, status and path of all files.
DBCC CHECKPRIMARYFILE('D:\SQLData\AdventureWorksDW2012_Data.mdf',3) WITH NO_INFOMSGS
Use DBCC CHECKPRIMARYFILE Attach SQL Server Database Files
With all of this info in our hands, we can use this to provide a solution to the problem explained at the beginning of this tip. I will make use of this undocumented command, DBCC CHECKPRIMARYFILE, and combine it with CREATE DATABASE commands to generate a CREATE DATABASE FOR ATTACH statement for all databases we want to put on-line without having to write T-SQL code to do this.
We know that DBCC CHECKPRIMARYFILE needs as an input the physical primary file name, so it important to have this information somewhere. In this case, I will get the physical primary file names into a text file by using the bcp utility as follows:
exec sp_configure 'show advanced options', 1
go
reconfigure with override
go
exec sp_configure 'xp_cmdshell', 1
go
reconfigure with override
go
exec xp_cmdshell 'mkdir c:\temp'
go
exec xp_cmdshell 'bcp "select rtrim(physical_name) from sys.master_files where file_id=1 and db_name(database_id) not in (''master'', ''model'', ''tempdb'', ''distribution'', ''msdb'')" queryout "C:\temp\MasterDataFiles.txt" -T -c'
go
Here is what the file looks like after running this. You could also manually create this data or run a process periodically from your server that gets you this information, so you have it when needed.

The below code with use the DBCC CHECKPRIMARYFILE command via a cursor to generate the CREATE DATABASE FOR ATTACH code for each database from the list. The following code is easy and self-explanatory by itself.
set nocount on
declare @TSQLFileName varchar(max)
declare @TSQLCreateDatabase varchar(max)
declare @DatabaseName varchar(512)
declare @LogicalFileName varchar(4000)
declare @PhysicalFileName varchar(4000)
declare @TSQLDBCCPPRIMARYFILE_getdbname varchar(4000)
declare @TSQLDBCCPPRIMARYFILE_getdbfiles varchar(4000)
create table #MasterDataFiles (PhysicalFileName varchar(4000))
--saving physical file names into a txt file
bulk insert dbo.#masterdatafiles from 'c:\temp\masterdatafiles.txt'
with (rowterminator ='\n');
--reading the database name and all physical file names of each database
declare CursorPhysicalFileName cursor for
select PhysicalFileName
from #MasterDataFiles
open CursorPhysicalFileName
fetch next from CursorPhysicalFileName into @PhysicalFileName
while (@@FETCH_STATUS=0)
begin
SET @LogicalFileName=''
set @TSQLCreateDatabase=''
set @TSQLFileName=''
create table #db (property sql_variant, value sql_variant)
create table #dbfiles(status int, fileid int, name varchar(100), filename varchar(512))
set @TSQLDBCCPPRIMARYFILE_getdbname='DBCC CHECKPRIMARYFILE ('''+@PhysicalFileName+''', 2)'
set @TSQLDBCCPPRIMARYFILE_getdbfiles='DBCC CHECKPRIMARYFILE ('''+@PhysicalFileName+''', 3)'
insert into #db exec (@TSQLDBCCPPRIMARYFILE_getdbname)
insert into #dbfiles exec (@TSQLDBCCPPRIMARYFILE_getdbfiles)
select @DatabaseName = cast(value as varchar(512))from #db where property='Database Name'
-- Now we will create the CREATE DATABASE FOR ATTACH code dynamically
declare CursorFile cursor for
select CAST( [filename] AS VARCHAR(MAX))
from #dbfiles
open CursorFile
fetch next from CursorFile into @LogicalFileName
while (@@FETCH_STATUS=0)
begin
set @TSQLFileName=@TSQLFileName + '(FILENAME=N'''+
LTRIM(RTRIM(@LogicalFileName)) + '''),' + char(13)
fetch next from CursorFile into @LogicalFileName
end
close CursorFile
deallocate CursorFile
set @TSQLCreateDatabase= 'CREATE DATABASE ' + @DatabaseName + ' ON '+ char(13)
+ SUBSTRING(@TSQLFileName, 1,LEN(@TSQLFileName) - 2 ) + CHAR(13)+ 'FOR ATTACH;'
print @TSQLCreateDatabase
drop table #dbfiles
drop table #db
fetch next from CursorPhysicalFileName into @PhysicalFileName
end
close CursorPhysicalFileName
deallocate CursorPhysicalFileName
drop table #MasterDataFiles
set nocount off
As you can see the output is as follows, which can then be copied and pasted into a new query window to attach all the databases in a few seconds.

Note that the use of DBCC undocumented commands must be done with extreme caution and first tested in non-production environments. Many of them can be dangerous and affect your database server if you don’t really know how they work.
Next Steps
- Read these additional articles related to DBCC statements
- DBCC (Transact-SQL)
- DBCC – Undocumented commands
- List Available DBCC Commands
- CREATE DATABASE (SQL Server Transact-SQL)
- SQL Server DBCC Tips

Percy Reyes has a Bach. Systems Engineering and Certified Senior Database Administrator focused on Microsoft SQL Server Internals with over 15+ years of extensive experience managing database servers on SQL Server 6.5, 7.0, 2000, 2005, 2008, 2008 R2, 2012, 2014, 2016, and 2017. He has in-depth knowledge and strong experience in database administration of SQL Server including installation and upgrading the database server and client tools, allocation system storage and planning future storage requirements for the database system, Backup/Restore operations, Indexing, Statistics, Integrity Checks, Database Maintenance, Database Reduction, Storage Engine, Replication, Monitoring, Optimization and Performance Tuning, In-Memory OLTP, Security and Compliance, Scalability, High Availability, Mirroring, Log Shipping, AlwaysOn, Failover Clustering, FileStream, Partitioning Very Large Tables, Disaster Recovery, Troubleshooting, and internals issues. Percy is always contributing to the SQL Community via twitter (@percyreyes) and writing in his blog and also as a frequent speaker about SQL Server technologies for over 10+ years at local user group meetings, webcasts, and national conferences. He can be reached at https://www.percyreyes.com.
- MSSQLTips Awards: Rookie of the Year Contender – 2014


