I have a query that views some information about an entire instance of databases. Using Extended Properties, I have also added information on database level to what customer the database belongs to, among other things.
To view all the information collectively, my query looks like this:
SELECT d.database_id AS [ID],
d.NAME AS [Database Name],
Round(Sum(mf.size) * 8 / 1024, 0) AS [Size (MB)],
d.state_desc AS [State],
d.is_read_only AS [Read Only],
d.create_date AS [Created Date],
Max(CASE
WHEN SEP.NAME = 'Shared' THEN value
END) AS [Shared],
Max(CASE
WHEN SEP.NAME = 'Product' THEN value
END) AS [Product],
Max(CASE
WHEN SEP.NAME = 'Customer' THEN value
END) AS [Customer]
FROM sys.master_files mf
INNER JOIN sys.databases d
ON d.database_id = mf.database_id,
sys.extended_properties SEP
WHERE d.database_id > 4 -- Skip system databases
GROUP BY d.database_id,
d.NAME,
d.state_desc,
d.is_read_only,
d.create_date
ORDER BY d.NAME
And the results become this:
As you can see, all Extended Properties "Shared", "Product", and "Customer" will be overwritten by the first database's Extended Properties. In reality, if the query worked as intended, it would be something like this instead:
Notice the emphasis on the last three columns. I have tried to group the query on SEP.name
and SEP.value
, but the result have not been to any help. How does one fix this?
Best Answer
Your query is missing the joining clause against
sys.extended_properties
. It's currently doing the cartesian product against the previous join result (notice the comma at the end of the first join and no condition on theWHERE
linking the tables).I'd recommend always explicitly writing the
JOIN
operator (and avoid writing the relationships in theWHERE
) since it makes the query more readable. If you want to apply cartesian just writeCROSS JOIN
.Extended properties on database object are tricky because their record on
sys.extended_properties
have no id (they are listed as 0). The documentation says that database objects are listed withclass = 0
, so we are gonna query those:The way you can retrieve these is through the system function sys.fn_listextendedproperty, by supplying all parameters as
DEFAULT
:However, this will only retrieve the extended properties of the database in which you are executing the function. So to see
ADatabase
's extended properties you will need to writeADatabase.sys.fn_listextendedproperty(...)
. This means that you will require a dynamic, database by database solution to correctly retrieve all these (in which case you can use thesys.extended_properties
while preceding the correspondingUSE <DatbaseName>
before).The following solution uses a temporary table and a cursor to retrieve all databases extended properties and finally join with your query by
database_id
. I've tested it and ran successfully (but always review it!).