Metadata enrichment dashboards
Use Lakehouse (MDLH) to build dashboards that track documentation coverage, ownership, tags, and key governance attributes across your data estate. These examples help you measure enrichment progress and identify where documentation, ownership, or tagging needs improvement.
Before you begin
Before you run these queries, make sure:
- Your Lakehouse setup is complete and Lakehouse is enabled for your organization. If setup isn't complete, see Get started with Lakehouse.
- The Gold layer is set up for your SQL engine. See Set up gold layer in Snowflake. For Databricks (Databricks setup guide) or BigQuery (BigQuery setup guide) setups, contact your Atlan Customer Success team.
You can query the DATAPRODUCT_ENTITY, TABLE_ENTITY, COLUMN_ENTITY, SCHEMA_ENTITY, and POWERBIWORKSPACE_ENTITY tables (and related metadata tables) in the Lakehouse to power enrichment dashboards.
Coverage by entity type
Use this query to generate high-level statistics for core entities such as tables, columns, schemas, data products, and Power BI workspaces. You can use the output to build a scorecard that tracks how many assets have descriptions, owners, and tags populated.
-- Get the stats for the entities such as table, column, schema, powerbiworkspace
-- e.g. how many entities have description, how many have owners, how many have tags, etc.
--
WITH entity_stats AS (
SELECT
'DATA_PRODUCT' AS entity_type,
COUNT(*) AS total_count,
COUNT(
CASE
WHEN NOT description IS NULL
AND TRIM(description) <> '' THEN 1
END
) AS with_description,
COUNT(
CASE
WHEN description IS NULL
OR TRIM(description) = '' THEN 1
END
) AS without_description,
COUNT(
CASE
WHEN NOT description IS NULL
AND TRIM(description) = TRIM(name) THEN 1
END
) AS description_matches_name,
COUNT(
CASE
WHEN ARRAY_SIZE(ownergroups) >0
OR ARRAY_SIZE(ownerusers) >0 THEN 1
END
) AS with_owners,
COUNT(
CASE
WHEN ARRAY_SIZE(ownergroups) = 0
OR ARRAY_SIZE(ownerusers) = 0 THEN 1
END
) AS without_owners,
COUNT(
DISTINCT CASE
WHEN NOT tr.entityguid IS NULL THEN p.guid
END
) AS with_tags,
COUNT(
DISTINCT CASE
WHEN tr.entityguid IS NULL THEN p.guid
END
) AS without_tags
FROM
dataproduct_entity AS p
LEFT JOIN tag_relationship AS tr ON p.guid = tr.entityguid
GROUP BY
1
UNION ALL
SELECT
'TABLE_ENTITY' AS entity_type,
COUNT(*) AS total_count,
COUNT(
CASE
WHEN NOT description IS NULL
AND TRIM(description) <> '' THEN 1
END
) AS with_description,
COUNT(
CASE
WHEN description IS NULL
OR TRIM(description) = '' THEN 1
END
) AS without_description,
COUNT(
CASE
WHEN NOT description IS NULL
AND TRIM(description) = TRIM(name) THEN 1
END
) AS description_matches_name,
COUNT(
CASE
WHEN ARRAY_SIZE(ownergroups) >0
OR ARRAY_SIZE(ownerusers) >0 THEN 1
END
) AS with_owners,
COUNT(
CASE
WHEN ARRAY_SIZE(ownergroups) = 0
OR ARRAY_SIZE(ownerusers) = 0 THEN 1
END
) AS without_owners,
COUNT(
DISTINCT CASE
WHEN NOT tr.entityguid IS NULL THEN t.guid
END
) AS with_tags,
COUNT(
DISTINCT CASE
WHEN tr.entityguid IS NULL THEN t.guid
END
) AS without_tags
FROM
table_entity AS t
LEFT JOIN tag_relationship AS tr ON t.guid = tr.entityguid
GROUP BY
1
UNION ALL
SELECT
'COLUMN_ENTITY' AS entity_type,
COUNT(*) AS total_count,
COUNT(
CASE
WHEN NOT description IS NULL
AND TRIM(description) <> '' THEN 1
END
) AS with_description,
COUNT(
CASE
WHEN description IS NULL
OR TRIM(description) = '' THEN 1
END
) AS without_description,
COUNT(
CASE
WHEN NOT description IS NULL
AND TRIM(description) = TRIM(name) THEN 1
END
) AS description_matches_name,
COUNT(
CASE
WHEN ARRAY_SIZE(ownergroups) >0
OR ARRAY_SIZE(ownerusers) >0 THEN 1
END
) AS with_owners,
COUNT(
CASE
WHEN ARRAY_SIZE(ownergroups) = 0
OR ARRAY_SIZE(ownerusers) = 0 THEN 1
END
) AS without_owners,
COUNT(
DISTINCT CASE
WHEN NOT tr.entityguid IS NULL THEN c.guid
END
) AS with_tags,
COUNT(
DISTINCT CASE
WHEN tr.entityguid IS NULL THEN c.guid
END
) AS without_tags FROM
column_entity AS c
LEFT JOIN tag_relationship AS tr ON c.guid = tr.entityguid
UNION ALL
SELECT
'SCHEMA_ENTITY' AS entity_type,
COUNT(*) AS total_count,
COUNT(
CASE
WHEN NOT description IS NULL
AND TRIM(description) <> '' THEN 1
END
) AS with_description,
COUNT(
CASE
WHEN description IS NULL
OR TRIM(description) = '' THEN 1
END
) AS without_description,
COUNT(
CASE
WHEN NOT description IS NULL
AND TRIM(description) = TRIM(name) THEN 1
END
) AS description_matches_name,
COUNT(
CASE
WHEN ARRAY_SIZE(ownergroups) >0
OR ARRAY_SIZE(ownerusers) >0 THEN 1
END
) AS with_owners,
COUNT(
CASE
WHEN ARRAY_SIZE(ownergroups) = 0
OR ARRAY_SIZE(ownerusers) = 0 THEN 1
END
) AS without_owners,
COUNT(
DISTINCT CASE
WHEN NOT tr.entityguid IS NULL THEN s.guid
END
) AS with_tags,
COUNT(
DISTINCT CASE
WHEN tr.entityguid IS NULL THEN s.guid
END
) AS without_tags
FROM
schema_entity AS s
LEFT JOIN tag_relationship AS tr ON s.guid = tr.entityguid
GROUP BY
1
UNION ALL
SELECT
'POWERBIWORKSPACE_ENTITY' AS entity_type,
COUNT(*) AS total_count,
COUNT(
CASE
WHEN NOT description IS NULL
AND TRIM(description) <> '' THEN 1
END
) AS with_description,
COUNT(
CASE
WHEN description IS NULL
OR TRIM(description) = '' THEN 1
END
) AS without_description,
COUNT(
CASE
WHEN NOT description IS NULL
AND TRIM(description) = TRIM(name) THEN 1
END
) AS description_matches_name,
COUNT(
CASE
WHEN ARRAY_SIZE(ownergroups) >0
OR ARRAY_SIZE(ownerusers) >0 THEN 1
END
) AS with_owners,
COUNT(
CASE
WHEN ARRAY_SIZE(ownergroups) = 0
OR ARRAY_SIZE(ownerusers) = 0 THEN 1
END
) AS without_owners,
COUNT(
DISTINCT CASE
WHEN NOT tr.entityguid IS NULL THEN pws.guid
END
) AS with_tags,
COUNT(
DISTINCT CASE
WHEN tr.entityguid IS NULL THEN pws.guid
END
) AS without_tags
FROM
powerbiworkspace_entity AS pws
LEFT JOIN tag_relationship AS tr ON pws.guid = tr.entityguid
)
SELECT
entity_type,
total_count,
with_description,
without_description,
description_matches_name,
with_owners,
without_owners,
with_tags,
without_tags
FROM
entity_stats
ORDER BY
entity_type;
You can visualize this output as a bar or heat-map style dashboard that shows documentation, ownership, and tagging coverage by entity type.
Governance coverage for data products
Use this query to audit governance-related attributes on data products for a specific owner. This helps you monitor whether status, sensitivity, criticality, lifecycle, grain, and data governor fields are consistently populated.
WITH custom_attr AS (
SELECT
entityguid,
MAX(CASE WHEN attributedisplayname = 'Data Governor'
AND attributevalue <> '' THEN 'Yes' ELSE 'No' END) AS DATA_GOVERNOR_POPULATED,
MAX(CASE WHEN attributedisplayname = 'Data Lifecycle'
AND attributevalue <> '' THEN 'Yes' ELSE 'No' END) AS DATA_LIFECYCLE_POPULATED,
MAX(CASE WHEN attributedisplayname = 'data_grain'
AND attributevalue <> '' THEN 'Yes' ELSE 'No' END) AS DATA_GRAIN_POPULATED
FROM custommetadata_relationship
WHERE setdisplayname IN ('Clinical Study Context', 'Data Governance')
GROUP BY entityguid
)
SELECT
p.NAME AS DATA_PRODUCT_NAME,
p.OWNERUSERS,
CASE WHEN p.daapstatus IS NOT NULL AND p.daapstatus <> '' THEN 'Yes' ELSE 'No' END AS STATUS_POPULATED,
CASE WHEN p.daapsensitivity IS NOT NULL AND p.daapsensitivity <> '' THEN 'Yes' ELSE 'No' END AS SENSITIVITY_POPULATED,
CASE WHEN p.daapcriticality IS NOT NULL AND p.daapcriticality <> '' THEN 'Yes' ELSE 'No' END AS CRITICALITY_POPULATED,
CASE WHEN ARRAY_SIZE(p.daapoutputportguids) > 0 THEN 'Yes' ELSE 'No' END AS OUTPUT_PORTS_POPULATED,
CASE WHEN p.description IS NOT NULL AND p.description <> '' THEN 'Yes' ELSE 'No' END AS DESCRIPTION_POPULATED,
CASE WHEN ARRAY_SIZE(p.readme) > 0 THEN 'Yes' ELSE 'No' END AS README_POPULATED,
CASE WHEN ARRAY_SIZE(p.meanings) > 0 THEN 'Yes' ELSE 'No' END AS TERMS_POPULATED,
CASE WHEN p.CERTIFICATESTATUS IS NOT NULL AND p.CERTIFICATESTATUS <> '' THEN 'Yes' ELSE 'No' END AS CERTIFICATE_POPULATED,
ca.DATA_GOVERNOR_POPULATED,
ca.DATA_LIFECYCLE_POPULATED,
ca.DATA_GRAIN_POPULATED
FROM DATAPRODUCT_ENTITY p
LEFT JOIN custom_attr ca ON p.guid = ca.entityguid
WHERE ARRAY_CONTAINS('edgar.degroot'::string, p.OWNERUSERS)
ORDER BY p.NAME;
Update the WHERE clause to target specific owners, domains, or product collections. You can build a dashboard that highlights which data products are missing key governance attributes and track improvement over time.