Inserting DBCC CHECKDB Results Into A Table
- 3
- Add a Comment
Hello again and welcome back!
I thought today’s posting to my blog should cover how to get the results of DBCC CHECKDB into a table. Unfortunately, Microsoft does not allow you easily per se to insert the results into a table so that you might be able to generate administrative reports off of. Well in my case that is exactly why I developed this process… to generate administrative reports off of.
Now what I did as you will see in the T-SQL scripts below, I created a table based upon the result set of the DBCC CHECKDB execution. Once I had the column names and data types I went ahead and created the table. The next step was to write a stored procedure that would iterate through all databases on the server, run the DBCC CHECKDB statement and record the output into the table I just created. So after much testing and a little taste of success I give you the scripts below. I call the stored procedure in a SQL Server Agent job and schedule the job to run in the early hours of the morning and ’off peak’ hours. So in the morning I can review the results of DBCC CHECKDB from the previous night. Now you can modify this process to just append the data or just truncate it like I did. I hope you find this code helpful!… Let us know!…
Here is the table script (this script is for the SQL Server 2005 CHECKDB output)
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
SET ANSI_PADDING ON
GO
CREATE TABLE [dbo].[CheckDBResult](
[ServerName] [varchar](100) COLLATE SQL_Latin1_General_CP1_CI_AS NULL,
[Error] [int] NULL,
[Level] [int] NULL,
[State] [int] NULL,
[MessageText] [varchar](7000) COLLATE SQL_Latin1_General_CP1_CI_AS NULL,
[RepairLevel] [int] NULL,
[Status] [int] NULL,
[DbId] [int] NULL,
[Id] [int] NULL,
[IndId] [int] NULL,
[PartitionId] [int] NULL,
[AllocUnitId] [int] NULL,
[File] [int] NULL,
[Page] [int] NULL,
[Slot] [int] NULL,
[RefFile] [int] NULL,
[RefPage] [int] NULL,
[RefSlot] [int] NULL,
[Allocation] [int] NULL,
[insert_date] [datetime] NOT NULL CONSTRAINT [DF_CheckDBResult_insert_date] DEFAULT (getdate())
) ON [PRIMARY]
GO
SET ANSI_PADDING OFF
Here is the CREATE PROCEDURE script that utilizes the CHECKDB 2005 output and here is the T-SQL syntax to execute the procedure: EXEC mDBMaintenance ‘Lumiere’ <- server name to run the script against
EXEC Admin_GetCheckDBResults ’server name’
set ANSI_NULLS ON
set QUOTED_IDENTIFIER ON
GO
CREATE PROCEDURE [dbo].[Admin_GetCheckDBResults]
@ServerName VARCHAR(100)
AS
DECLARE @Database SYSNAME
– Remove Previous Weeks Results
TRUNCATE TABLE DBA_Admin.dbo.CheckDBResult
DECLARE cDatabases CURSOR FOR
SELECT [name] from master..sysdatabases AS sdb
WHERE sdb.[name] NOT IN (‘tempdb’)
OPEN cDatabases
FETCH FROM cdatabases INTO @Database
WHILE ( @@FETCH_STATUS = 0)
BEGIN
SET NOCOUNT ON
INSERT INTO DBA_Admin.dbo.CheckDBResult(
Error,
[Level],
[State],
MessageText,
RepairLevel,
[Status],
[DbId],
Id,
IndId,
PartitionId, — specific to SQL Server 2005, remove for SQL Server 2000 results
AllocUnitId, — specific to SQL Server 2005, remove for SQL Server 2000 results
[File],
Page,
Slot,
RefFile,
RefPage,
RefSlot,
Allocation
)
EXEC (‘DBCC CHECKDB(”’ + @Database + ”’) WITH TABLERESULTS’)
FETCH FROM cdatabases INTO @Database
END
CLOSE cDatabases
DEALLOCATE cDatabases
– Remove all details except CHECKDB information
DELETE
FROM DBA_Admin.dbo.CheckDBResult
WHERE MessageText NOT LIKE ‘CHECKDB%’
– Update server Name
UPDATE DBA_Admin.dbo.CheckDBResult
SET ServerName = @ServerName
– Select Statment To Return Rows
SELECT ServerName,
MessageText,
Error,
[Level],
[State],
RepairLevel,
[Status],
[DbId],
Id,
IndId,
PartitionId, – specific to SQL Server 2005, remove for SQL Server 2000 results
AllocUnitId, – specific to SQL Server 2005, remove for SQL Server 2000 results
[File],
Page,
Slot,
RefFile,
RefPage,
RefSlot,
Allocation,
Insert_Date
FROM DBA_Admin.dbo.CheckDBResult
GO
Now as you can see I only want to see the last line in the DBCC CHECKDB command… however, you can modify it keep all the detail from the execution. I hope this code helps and let us know how you are using it!

3 Comments
John Zacharkan
June 23rd, 2009
at 8:19am
Nice work SQLSquirrel,
Fantastic to see how others go about monitoring their environments. What I like especially is the flexibility to query the results and make decisions as needed.
Couple of quick observations based on my SQL 2005 EE
Repairlevel is a varchar I’m using (255)
PartionID bigint
AllocUnitId bigint
Without these changes the procedure fails on insert when checkdb comes on a consistency error.
thanks greatly and keep up the great work.
cheers
Zach
James Kerr
July 10th, 2009
at 7:56am
Thank you very much, SQLSquirrel! I did use some of your code from above. I have a very large environment (50 instances of SQL2000 and SQL2005) and I am setting up a Master/Target Server Job to execute CHECKDB against all databases in an instance. But, I had a couple special requirements from my manager for this solution, and I ran into something with the first few rounds of testing.
First off, Zach above is correct. I also have SQL 2005 Enterprise and I had a few columns that didn’t match up. Thank you to Zach!
Second, we don’t care about any results if there is nothing wrong with the database, so we are using :
WITH NO_INFOMSGS, TABLERESULTS.
This will only return rows if there is actually something wrong with the database.
This is part of a larger solution for us, as we are also trying to retain some level of history for databases, file sizes, checkdb scans, etc. I have 4 tables in the master database that we are writting to: DatabaseList, DatabaseFileInfo, CheckDBScanList, and CheckDBErrors. Since the DatabaseList table is updated daily, I use this to build my cursor of work, excluding databases that no longer exist (expired rows). I use Database ID number for the CHECKDB command in my code, I find it much easier/cleaner than using the database name. Also, I exclude all four system databases. I am also tracking the scan in the CheckDBScanList table. This table gets a row with the start time just before calling the CHECKDB command, and writes stop time and a zero or one based on the results of the scan (if there is something in the #temp table from the scan, the scan “failed” and rows are written to CheckDBErrors, otherwise, the scan succeeded). Of course, after each scan, I truncate the #temp, just in case.
If you want more information, feel free to message me. Thanks!
James Kerr
sqlsquirrel
July 10th, 2009
at 6:54pm
Thanks to all of you for your thoughts and contributions… yes, yes as well as your corrections! :0) I know I appreciate it as well other SQL Server professionals that read this blog post.
All of you help to keep this blog going with your excellent feedback and insightful tips!