Blogs

Paul Kimmel's Blog

Tip 1: Querying the master Database

     

The master database in SQL Server contains all of the information about all of the other databases. You can query thee master database to find out things like all of the other databases on a server, tables on those databases, and schemas. I have used this approach before when building application generation/and ORM (object relational modeling) tools. For instance read the databases and list them. Let the user pick a database. Read that database’s tables and list those. Let the user pick the table and generate some kind of form based on this information.

One challenge you may encounter is that the master table has tables in schemas and depending on the approach you use to read the master tables it may or may not work. For example, if you use SQL Server Management Studio Express 2005 then you can query sys.databases in the master table to determine what databases or running on that server.

select * from sys.databases

The preceding query works in SQL Server Management Studio against the master database, but it does not work with ADO.NET in Visual Studio (at least the first time). When I used ADO.NET, the preceding query, and a SqlDataAdapter to fill a DataTable the code responded with an invalid object name sys.databases. By changing the table name to its SQL Server 2000 version (rewriting the query)

select * from master.dbo.sysdatabases

the code works and the exception no longer occurs. What’s really weird is that subsequently changing the query back to sys.databases no longer caused an exception either. I am still looking into whether this is an application caching issue, a connection caching issue, or because I have SQL Server Management Studio open. These flaky errors can consume a lot of time.

For the time being, if you get an invalid object error on ADO.NET code using a namespace other than dbo then try using the SQL 2000 version of the name, prefix the table, dbo, and a consolidated name for the table. (This looks like what the Data Source Wizard in Visual Studio is doing with databases like AdventureWorks.)

After a little examination it looks like the default database to connect to is not master, so even though master was expressed as the catalog argument in my connection string querying sys.databases without the database name caused the invalid object error. When I logged into SQL Server Management Studio and connected to the master database it seemed to resolve the problem in the code.

If you Google this issue—invalid object, sys.databases—you will see there is a very high noise ratio. Although of the hundreds of posts there is no single definitive answer. If you happen to know how to reproduce this error, why it occurs, then respond to this blog posting.

Published Nov 12 2009, 08:03 PM by Paul Kimmel (DevExpress)
Bookmark and Share

Comments

 

Ferdi said:

Hi Paul,

I have spent hours on end pulling out my hair at the exact same issue you face here.

Looking back at the days since SQL 7.0 there was always a problem with the '.' notation, since SQL has a hierarchy of objects and each construct (or parameter) refers to a table, view or stored proc, user context, database name and server name (have a look at the link www.mauvais.com/.../ZD-Distrib.htm).

Now looking back I have had issues on certain versions of SQL using the '.' notation, up until SQL 2000 SP3a; there was all sorts of problems with it, now especially since I used the '.' notation in table names it caused havoc.

The thing I learnt here was that enclosing the table names with [ ] brackets sorted out most of my issues, as the enclosing of an object name inside [ ] allows you to refer to table names with spaces or '.' inside the table name itself.

I have tried to execute the statement above (both executed the first time without failure; I am running SQL 2005 SP3).

I would suggest maybe giving it ago and try to enclose your user/table names with [ ] brackets and see if this does the trick (it did it for me on earlier version of SQL Server).

Thus try executing it as select * from [sys].[databases] and you should see a difference, if you don’t then this may also refer to security related issues, since you may not be connecting as the sys context to the master database.

November 12, 2009 5:49 PM
 

ijrussell said:

I thought that directly querying the master database was frowned upon; There are a number of system stored procedures that you should use instead.

You can get the schema information for each database through the GetSchema() methods on the Connection class in Ado.Net.

November 13, 2009 9:29 AM
 

heather said:

Paul speaking of querying the master...here is a routine I have used for years.  You can put in a search criteria (need %'s around your text) and will find it in any of the database objects.  This is a real time saver.

USE [master]

GO

SET ANSI_NULLS ON

GO

SET QUOTED_IDENTIFIER ON

GO

CREATE PROC [dbo].[dba_SearchDBServer]

@StringToFind NVARCHAR(1000)

AS

DECLARE @SQL NVARCHAR(4000)

SET @SQL = 'EXEC sp_MSForEachDB ' + '''' + 'USE [?]; PRINT ' + '''' + '''' +'?'  

+ '''' + '''' + '; EXEC master.dbo.dba_SearchDB ' + '''' + ''''

+ @StringToFind  + '''' + '''' + ', [?];' + ''''

PRINT @SQL

EXECUTE sp_executesql @SQL

November 13, 2009 11:14 AM
 

heather said:

Here is another that will search a particular database instance...

USE [master]

GO

SET ANSI_NULLS ON

GO

SET QUOTED_IDENTIFIER ON

GO

CREATE PROC [dbo].[dba_SearchDB]

@StringToFind NVARCHAR(1000)

,@DBName NVARCHAR(255)

AS

DECLARE @SQL NVARCHAR(4000) -- Work variable to hold dynamic SQL.

-- Do not lock anything, and do not get held up by any locks.

SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED

-- Ensure @StringToFind has at least one character wrapped by % symbols.

-- Ensure @StringToFind has at least 3 characters (one character and two '%' symbols).

IF LEN(@StringToFind) < 3

BEGIN

RAISERROR('There should be at least one character enclosed with percentage symbols.', 16, 1)

RETURN

END

-- Ensure @StringToFind starts with a %.

IF SUBSTRING(@StringToFind, 1, 1) <> '%'

BEGIN

RAISERROR('String should START with a percentage symbol.', 16, 1)

RETURN

END

-- Ensure @StringToFind ends with a %.

IF SUBSTRING(@StringToFind, LEN(@StringToFind), 1) <> '%'

BEGIN

RAISERROR('String should END with a percentage symbol.', 16, 1)

RETURN

END

-- Build @SQL to look for @StringToFind inside any table definitions.

SET @SQL = ' SELECT  ' +  '''' + @DBName + '''' + ' AS [Database Name]' + ','  

+  @DBName + '.dbo.sysobjects.name AS [Object Name],  '

+ '[Object Type] = ' + '''' + 'User Table' + ''''

+ ' FROM  ' +  @DBName + '.dbo.sysobjects INNER JOIN '

+ @DBName + '.dbo.syscolumns ON '  + @DBName + '.dbo.sysobjects.id =  ' + @DBName + '.dbo.syscolumns.id'

+ ' WHERE  ( ' + @DBName + '.dbo.syscolumns.name LIKE ' + '''' + @StringToFind + '''' + ')'

+ ' AND ' + @DBName + '.dbo.sysobjects.xtype = '  + '''' + 'U' + ''''

-- Set UNION command (want to combine the result).

SET @SQL = @SQL + '  UNION '  

-- Build @SQL to look for @StringToFind inside any view, rule, default, trigger, CHECK constraint, DEFAULT constraint, and stored procedure definitions.

SET @SQL = @SQL + ' SELECT  ' +  '''' + @DBName + '''' + ' AS [Database Name]' + ','  

+  @DBName + '.dbo.sysobjects.name AS [Object Name],  '

+ '[Object Type] = CASE ' + @DBName + '.dbo.sysobjects.xtype'  

+ ' WHEN ' + '''' + 'C' + '''' + ' THEN ' + '''' + 'CHECK constraint ' + ''''

+ ' WHEN ' + '''' + 'D' + '''' + ' THEN ' + '''' + 'Default or DEFAULT constraint ' + ''''

+ ' WHEN ' + '''' + 'F' + '''' + ' THEN ' + '''' + 'FOREIGN KEY constraint ' + ''''

+ ' WHEN ' + '''' + 'L' + '''' + ' THEN ' + '''' + 'Log ' + ''''

+ ' WHEN ' + '''' + 'FN' + '''' + ' THEN ' + '''' + 'Scalar function ' + ''''

+ ' WHEN ' + '''' + 'IF' + '''' + ' THEN ' + '''' + 'Inlined table-function ' + ''''

+ ' WHEN ' + '''' + 'P' + '''' + ' THEN ' + '''' + 'Stored procedure ' + ''''

+ ' WHEN ' + '''' + 'PK' + '''' + ' THEN ' + '''' + 'PPRIMARY KEY constraint ' + ''''

+ ' WHEN ' + '''' + 'RF' + '''' + ' THEN ' + '''' + 'Replication filter stored procedure ' + ''''

+ ' WHEN ' + '''' + 'S' + '''' + ' THEN ' + '''' + 'System table ' + ''''

+ ' WHEN ' + '''' + 'TF' + '''' + ' THEN ' + '''' + 'Table function ' + ''''

+ ' WHEN ' + '''' + 'TR' + '''' + ' THEN ' + '''' + 'Trigger ' + ''''

+ ' WHEN ' + '''' + 'U' + '''' + ' THEN ' + '''' + 'User table ' + ''''

+ ' WHEN ' + '''' + 'UQ' + '''' + ' THEN ' + '''' + 'UNIQUE constraint ' + ''''

+ ' WHEN ' + '''' + 'V' + '''' + ' THEN ' + '''' + 'View ' + ''''

+ ' WHEN ' + '''' + 'X' + '''' + ' THEN ' + '''' + 'Extended stored procedure ' + ''''

+ ' ELSE ' + '''' + 'Other' + ''''

+ ' END '

+ ' FROM  ' +  @DBName + '.dbo.sysobjects INNER JOIN '

+ @DBName + '.dbo.syscomments ON '  + @DBName + '.dbo.sysobjects.id =  ' + @DBName + '.dbo.syscomments.id'

+ ' WHERE  ( ' + @DBName + '.dbo.syscomments.text LIKE ' + '''' + @StringToFind + '''' + ')'

-- Order by Object type, then Object Name.

+ ' ORDER BY [Object Type], [Object Name]'

PRINT @SQL -- Useful for debugging.

-- Find the passed string.

EXECUTE sp_executesql @SQL

November 13, 2009 11:15 AM
More from DevExpress
Live Chat
Have a pre-sales question?
Need assistance with your evaluation?
We are here to help.
Chat is one of the many ways you can contact members of the DevExpress Team. We are available Monday-Friday between 8:30am and 5:00pm Pacific Time.
If you need additional product information, require pre-sales assistance, or want help with your order, write to us at info@devexpress.com or call us at
+1 (818) 844-3383.