Unity Catalog: Create Metastore and Enabling Unity Catalog in Azure

A metastore is the top-level container for data in Unity Catalog. Unity Catalog metastore register metadata about securable objects (such as tables, volumes, external locations, and shares) and the permissions that govern access to them.

Each metastore exposes a three-level namespace (catalog.schema.table) by which data can be organized. You must have one metastore for each region in which your organization operates. 

Microsoft said that Databricks began to enable new workspaces for Unity Catalog automatically on November 9, 2023, with a rollout proceeding gradually across accounts. Otherwise, we must follow the instructions in this article to create a metastore in your workspace region.

Preconditions

Before we begin

1. Microsoft Entra ID Global Administrator

The first Azure Databricks account admin must be a Microsoft Entra ID Global Administrator 

The first Azure Databricks account admin must be a Microsoft Entra ID Global Administrator at the time that they first log in to the Azure Databricks account console.

https://accounts.azuredatabricks.net

Upon first login, that user becomes an Azure Databricks account admin and no longer needs the Microsoft Entra ID Global Administrator role to access the Azure.

2. Premium Tire

Databricks workspaces Pricing tire must be Premium Tire.

3. The same region

Databricks region is in the same as ADLS’s region. Each region allows one metastore only.

Manual create metastore and enable unity catalog process

  1. Create an ADLS G2  (if you did not have)
    Create storage account and container to store manage table and volume data at the metastore level, the container will be the root storage for the unity catalog metastore
  2. Create an Access Connector for Azure Databricks
  3. Grant “Storage Blob Data Contributor” role to access Connector for Azure Databricks on ADLS G2 storage Account
  4. Enable Unity Catalog by creating Metastore and assigning to workspace

Step by step Demo

1. Check Entra ID role.

To check whether I am a Microsoft Entra ID Global Administrator role.

Azure Portal > Entra ID > Role and administrators

I am a Global Administrator

2. Create a container for saving metastore

Create a container at ROOT of ADLS Gen2

Since we have created an ADLS Gen2, directly move to create a container at root of ADLS.

3. Create an Access Connector for Databricks

If it did not automatically create while you create Azure databricks service, manual create one.

Azure portal > Access Connector for Databricks

once all required fields filled, we can see a new access connector created.

4. Grant Storage Blob Data Contributor to access Connector

Add “storage Blob data contributor” role assign to “access connector for Azure Databricks” I just created.

Azure Portal > ADLS Storage account > Access Control (IAM) > add role

Continue to add role assignment

5. Create a metastore

If you are an account admin, you can login accounts console, otherwise, ask your account admin to help.

before you begin to create a metastore, make sure

  • You must be an Azure Databricks account admin.
    The first Azure Databricks account admin must be a Microsoft Entra ID Global Administrator at the time that they first log in to the Azure Databricks account console. Upon first login, that user becomes an Azure Databricks account admin and no longer needs the Microsoft Entra ID Global Administrator role to access the Azure Databricks account. The first account admin can assign users in the Microsoft Entra ID tenant as additional account admins (who can themselves assign more account admins). Additional account admins do not require specific roles in Microsoft Entra ID.
  • The workspaces that you attach to the metastore must be on the Azure Databricks Premium plan.
  • If you want to set up metastore-level root storage, you must have permission to create the following in your Azure tenant

Login to azure databricks console 

azure databricks console: https://accounts.azuredatabricks.net/

Azure Databricks account console > Catalog > Create metastore.

  • Select the same region for your metastore.
    You will only be able to assign workspaces in this region to this metastore.
  • Container name and path
    The pattern is:
    <contain_name>@<storage_account_name>.dfs.core.windows.net/<path>
    For this demo I used this
    mainri-databricks-unitycatalog-metastore-eastus2@asamainriadls.dfs.core.windows.net/
  • Access connector ID
    The pattern is:
    /subscriptions/{sub-id}/resourceGroups/{rg-name}/providers/Microsoft.databricks/accessconnects/<connector-name>

Find out the Access connector ID

Azure portal > Access Connector for Azure Databricks

For this demo I used this
/subscriptions/9348XXXXXXXXXXX6108d/resourceGroups/mainri/providers/Microsoft.Databricks/accessConnectors/unity-catalog-access-connector-Premiu

Looks like this

Enable Unity catalog

Assign to workspace

To enable an Azure Databricks workspace for Unity Catalog, you assign the workspace to a Unity Catalog metastore using the account console:

  1. As an account admin, log in to the account console.
  2. Click Catalog.
  3. Click the metastore name.
  4. Click the Workspaces tab.
  5. Click Assign to workspace.
  6. Select one or more workspaces. You can type part of the workspace name to filter the list.
  7. Scroll to the bottom of the dialog, and click Assign.
  8. On the confirmation dialog, click Enable.

Account console > Catalog > select the metastore >

Workspace tag > Assign to workspace

click assign

Validation the unity catalog enabled

Open workspace, we can see the metastore has been assigned to workspace.

Now, we have successfully created metastore and enabled unity catalog.

Please do not hesitate to contact me if you have any questions at William . chen @ mainri.ca

(remove all space from the email account 😊)

Unity Catalog in Databricks

Unity Catalog is a fine-grained data governance solution for data present in a Data Lake for managing data governance, access control, and centralizing metadata across multiple workspaces. Unity Catalog provides centralized access control, auditing, lineage, and data discovery capabilities across Azure Databricks workspaces. It brings a new layer of data management and security to your Databricks environment

Unity Catalog provides centralized access control, auditing, lineage, and data discovery capabilities across Azure Databricks workspaces.

Key features of Unity Catalog include

  • Define once, secure everywhere: Unity Catalog offers a single place to administer data access policies that apply across all workspaces.
  • Standards-compliant security model: Unity Catalog’s security model is based on standard ANSI SQL and allows administrators to grant permissions in their existing data lake using familiar syntax, at the level of catalogs, schemas (also called databases), tables, and views.
  • Built-in auditing and lineage: Unity Catalog automatically captures user-level audit logs that record access to your data. Unity Catalog also captures lineage data that tracks how data assets are created and used across all languages.
  • Data discovery: Unity Catalog lets you tag and document data assets, and provides a search interface to help data consumers find data.
  • System tables (Public Preview): Unity Catalog lets you easily access and query your account’s operational data, including audit logs, billable usage, and lineage.

Unity Catalog object model

The hierarchy of database objects in any Unity Catalog metastore is divided into three levels, represented as a three-level namespace (catalog.schema.table-etc) 

Metastore

The metastore is the top-level container for metadata in Unity Catalog. It registers metadata about data and AI assets and the permissions that govern access to them. For a workspace to use Unity Catalog, it must have a Unity Catalog metastore attached.

Object hierarchy in the metastore

In a Unity Catalog metastore, the three-level database object hierarchy consists of catalogs that contain schemas, which in turn contain data and AI objects, like tables and models.

Level one: Catalogs are used to organize your data assets and are typically used as the top level in your data isolation scheme.

Level two: Schemas (also known as databases) contain tables, views, volumes, AI models, and functions.

Level three: Volumes, Tables, Views, Functions, Models (AI models packaged with MLflow)

Working with database objects in Unity Catalog

Working with database objects in Unity Catalog is very similar to working with database objects that are registered in a Hive metastore, with the exception that a Hive metastore doesn’t include catalogs in the object namespace. You can use familiar ANSI syntax to create database objects, manage database objects, manage permissions, and work with data in Unity Catalog. You can also create database objects, manage database objects, and manage permissions on database objects using the Catalog Explorer UI.

Granting and revoking access to database objects

You can grant and revoke access to securable objects at any level in the hierarchy, including the metastore itself. Access to an object implicitly grants the same access to all children of that object, unless access is revoked.


GRANT CREATE TABLE ON SCHEMA mycatalog.myschema TO `finance-team`;

Comparison of Unity Catalog, External Data Source, External Table, Mounting Data and Metastore

Comparison including the Databricks Catalog (Unity Catalog) alongside Mounting Data, External Data Source, External Table and Metastore:

FeatureDatabricks Catalog (Unity Catalog)Mounting DataExternal Data SourceExternal TableMetastore (Hive Metastore)
PurposeCentralized governance and access control for data across multiple workspaces and environments.Map cloud storage to DBFSQuery external databases directlyQuery external data in cloud storage via SQLStore metadata (schemas, table locations) for databases and tables in Databricks and Spark.
Data AccessSQL-based access to tables, views, and databases with unified governance.File-level access (Parquet, CSV, etc.)Database-level access (via JDBC/ODBC)Table-level access with metadata in DatabricksProvides table and schema information to Spark SQL, Hive, and Databricks.
SetupDefine catalog, databases, tables, views, and enforce permissions centrally.Mount external storage in DBFSConfigure connector (JDBC/ODBC)Create an external table with storage locationAutomatically manages metadata for tables and databases; can be customized or integrated with external metastores.
GovernanceCentralized governance, RBAC, column-level security, and audit logs.Managed by storage providerManaged by the external databaseManaged by external storage permissionsBasic governance, mainly for schema management; limited fine-grained access control.
ProsCentralized access control, auditing, lineage, and security across multiple environments.Easy access to filesNo need to copy data, works with SQL queriesAllows SQL queries on external dataSimplifies metadata management for large datasets and integrates seamlessly with Spark and Databricks.
ConsRequires Unity Catalog setup, and governance policies must be defined for all data assets.No built-in governanceLatency issues with external databasesMetadata management requires setupLacks advanced governance features like RBAC, auditing, and data lineage.
When to UseWhen you need centralized governance, access control, auditing, and security for data assets across multiple workspaces or cloud environments.When you need direct access to files stored externally, without ingestion.When you want to query external databases without moving the data.When you want SQL-based access to external files without copying them into Databricks.When you need basic schema and metadata management for tables and databases used by Databricks or Spark.

Add a new user to workspace

To allow another user to use your Azure Databricks workspace, follow these steps:

1. Log in to Databricks

Log in to the Azure Databricks workspace as a workspace admin.

2. Setting

Click your username in the top bar of the Azure Databricks workspace and select Settings.

3. Navigate to the Identity and access tab.

Next to Users, click Manage.

4. Click Add User.

Select an existing user 

Select an existing user to assign to the workspace or click Add new to create a new user. You can add any user who belongs to the Microsoft Entra ID (formerly Azure Active Directory) tenant of your Azure Databricks workspace.

A few Important Terminology of Databricks

Azure Databricks is a managed platform for running Apache Spark jobs. In this post, I’ll go through some key Databricks terms to give you an overview of the different points you’ll use when running Databricks jobs (sorted by alphabet):

Catalog (Unity Catalog)

the Unity Catalog is a feature that provides centralized governance for data, allowing you to manage access to data across different Databricks workspaces and cloud environments. It helps define permissions, organize tables, and manage metadata, supporting multi-cloud and multi-workspace environments. Key benefits include:

  • Support for multi-cloud data governance.
  • Centralized access control and auditing.
  • Data lineage tracking.

Delta table

A Delta table is a data management solution provided by Delta Lake, an open-source storage layer that brings ACID transactions to big data workloads. A Delta table stores data as a directory of files on cloud object storage and registers table metadata to the metastore within a catalog and schema. By default, all tables created in Databricks are Delta tables.

External tables

External tables are tables whose data lifecycle, file layout, and storage location are not managed by Unity Catalog. Multiple data formats are supported for external tables.


CREATE EXTERNAL TABLE my_external_table (
  id INT,
  name STRING,
  age INT
)
LOCATION 'wasbs://[container]@[account].blob.core.windows.net/data/';

External Data Source

A connection to a data store that isn’t natively in Databricks but can be queried through a connection.

External Data Sources are typically external databases or data services (e.g., Azure SQL Database, Azure Synapse Analytics, Amazon RDS, or other relational or NoSQL databases). These sources are accessed via connectors (JDBC, ODBC, etc.) within Databricks.


jdbcUrl = "jdbc:sqlserver://[server].database.windows.net:1433;database=[database]"
connectionProperties = {
  "user" : "username",
  "password" : "password",
  "driver" : "com.microsoft.sqlserver.jdbc.SQLServerDriver"
}
df = spark.read.jdbc(jdbcUrl, "[table]", connectionProperties)

Hive Metastore

The Hive Metastore is the metadata repository for the data in Databricks, storing information about tables and databases. It’s used by the Spark SQL engine to manage metadata for the tables and to store information like schemas, table locations, and partitions. In Azure Databricks:

  • Schemas: Column names, types, and table structure.
  • Table locations: The path to where the actual data resides (in HDFS, Azure Data Lake, S3, etc.).
  • Partitions: If the table is partitioned, the metadata helps optimize query performance.

By default, each Databricks workspace has its own managed Hive metastore.

You can also connect to an external Hive metastore that is shared across multiple Databricks workspaces or use Azure-managed services like Azure SQL Database for Hive metadata storage.

Managed tables

Managed tables are the preferred way to create tables in Unity Catalog. Unity Catalog fully manages their lifecycle, file layout, and storage. Unity Catalog also optimizes their performance automatically. Managed tables always use the Delta table format.

Managed tables reside in a managed storage location that you reserve for Unity Catalog. Because of this storage requirement, you must use CLONE or CREATE TABLE AS SELECT (CTAS) if you want to copy existing Hive tables to Unity Catalog as managed tables.

Mounting Data

Mounting external storage into Databricks as if it’s part of the Databricks File System (DBFS)


dbutils.fs.mount(
    source="wasbs://[container]@[account].blob.core.windows.net/",
    mount_point="/mnt/mydata",
    extra_configs={"fs.azure.account.key.[account].blob.core.windows.net": "[account_key]"}
)

Workflows

In Databricks, Workflows are a way to orchestrate data pipelines, machine learning tasks, and other computational processes. Workflows allow you to automate the execution of notebooks, Python scripts, JAR files, or any other job task within Databricks and run them on a schedule, trigger, or as part of a complex pipeline.

Key Components of Workflows in Databricks:

Jobs: Workflows in Databricks are typically managed through jobs. A job is a scheduled or triggered run of a notebook, script, or other tasks in Databricks. Jobs can consist of a single task or multiple tasks linked together.

Task: Each task in a job represents an individual unit of work. You can have multiple tasks in a job, which can be executed sequentially or in parallel.

Triggers: Workflows can be triggered manually, based on a schedule (e.g., hourly, daily), or triggered by an external event (such as a webhook).

Cluster: When running a job in a workflow, you need to specify a Databricks cluster (either an existing cluster or one that is started just for the job). Workflows can also specify job clusters, which are clusters that are spun up and terminated automatically for the specific job.

Types of Workflows
  1. Single-task Jobs: These jobs consist of just one task, like running a Databricks notebook or a Python/Scala/SQL script. You can schedule these jobs to run at specific intervals or trigger them manually.
  2. Multi-task Workflows: These workflows are more complex and allow for creating pipelines of interdependent tasks that can be run in sequence or in parallel. Each task can have dependencies on the completion of previous tasks, allowing you to build complex pipelines that branch based on results.Example: A data pipeline might consist of three tasks:
    • Task 1: Ingest data from a data lake into a Delta table.
    • Task 2: Perform transformations on the ingested data.
    • Task 3: Run a machine learning model on the transformed data.
  3. Parameterized Workflows: You can pass parameters to a job when scheduling it, allowing for more dynamic behavior. This is useful when you want to run the same task with different inputs (e.g., processing data for different dates).
Creating Workflows in Databricks

Workflows can be created through the Jobs UI in Databricks or programmatically using the Databricks REST API.

Example of Creating a Simple Workflow:
  1. Navigate to the Jobs Tab:
    • In Databricks, go to the Jobs tab in the workspace.
  2. Create a New Job:
    • Click Create Job.
    • Specify the name of the job.
  3. Define a Task:
    • Choose a task type (Notebook, JAR, Python script, etc.).
    • Select the cluster to run the job on (or specify a job cluster).
    • Add parameters or libraries if required.
  4. Schedule or Trigger the Job:
    • Set a schedule (e.g., run every day at 9 AM) or choose manual triggering.
    • You can also configure alerts or notifications (e.g., send an email if the job fails).
Multi-task Workflow Example:
  1. Add Multiple Tasks:
    • After creating a job, you can add more tasks by clicking Add Task.
    • For each task, you can specify dependencies (e.g., Task 2 should run only after Task 1 succeeds).
  2. Manage Dependencies:
    • You can configure tasks to run in sequence or in parallel.
    • Define whether a task should run on success, failure, or based on a custom condition.
Key Features of Databricks Workflows:
  1. Orchestration: Allows for complex job orchestration, including dependencies between tasks, retries, and conditional logic.
  2. Job Scheduling: You can schedule jobs to run at regular intervals (e.g., daily, weekly) using cron expressions or Databricks’ simple scheduler.
  3. Parameterized Runs: Pass parameters to notebooks, scripts, or other tasks in the workflow, allowing dynamic control of jobs.
  4. Cluster Management: Workflows automatically handle cluster management, starting clusters when needed and shutting them down after the job completes.
  5. Notifications: Workflows allow setting up notifications on job completion, failure, or other conditions. These notifications can be sent via email, Slack, or other integrations.
  6. Retries: If a job or task fails, you can configure it to automatically retry a specified number of times before being marked as failed.
  7. Versioning: Workflows can be versioned, so you can track changes and run jobs based on different versions of a notebook or script.
Common Use Cases for Databricks Workflows:
  • ETL Pipelines: Automating the extraction, transformation, and loading (ETL) of data from source systems to a data lake or data warehouse.
  • Machine Learning Pipelines: Orchestrating the steps involved in data preprocessing, model training, evaluation, and deployment.
  • Batch Processing: Scheduling large-scale data processing tasks to run on a regular basis.
  • Data Ingestion: Automating the ingestion of raw data into Delta Lake or other storage solutions.
  • Alerts and Monitoring: Running scheduled jobs that trigger alerts based on conditions in the data (e.g., anomaly detection).

KQL query map SQL query

To those whom are familiar SQL query syntax, but new to KQL. The following table shows sample queries in SQL and their KQL equivalents.

CategorySQL QueryKusto QueryLearn more
Select data from tableSELECT * FROM dependenciesdependenciesTabular expression statements
SELECT name, resultCode FROM dependenciesdependencies | project name, resultCodeproject
SELECT TOP 100 * FROM dependenciesdependencies | take 100take
Null evaluationSELECT * FROM dependencies
WHERE resultCode IS NOT NULL
dependencies
| where isnotnull(resultCode)
isnotnull()
Comparison operators (date)SELECT * FROM dependencies
WHERE timestamp > getdate()-1
dependencies
| where timestamp > ago(1d)
ago()
SELECT * FROM dependencies
WHERE timestamp BETWEEN ... AND ...
dependencies
| where timestamp between (datetime(2016-10-01) .. datetime(2016-11-01))
between
Comparison operators (string)SELECT * FROM dependencies
WHERE type = "Azure blob"
dependencies
| where type == "Azure blob"
Logical operators
-- substring
SELECT * FROM dependencies
WHERE type like "%blob%"
// substring
dependencies
| where type has "blob"
has
-- wildcard
SELECT * FROM dependencies
WHERE type like "Azure%"
// wildcard
dependencies
| where type startswith "Azure"
// or
dependencies
| where type matches regex "^Azure.*"
startswith
matches regex
Comparison (boolean)SELECT * FROM dependencies
WHERE !(success)
dependencies
| where success == False
Logical operators
Grouping, AggregationSELECT name, AVG(duration) FROM dependencies
GROUP BY name
dependencies
| summarize avg(duration) by name
summarize
avg()
DistinctSELECT DISTINCT name, type FROM dependenciesdependencies
| summarize by name, type
summarize
distinct
SELECT name, COUNT(DISTINCT type)
FROM dependencies
GROUP BY name
dependencies
| summarize by name, type | summarize count() by name
// or approximate for large sets
dependencies
| summarize dcount(type) by name
count()
dcount()
Column aliases, ExtendingSELECT operationName as Name, AVG(duration) as AvgD FROM dependencies
GROUP BY name
dependencies
| summarize AvgD = avg(duration) by Name=operationName
Alias statement
SELECT conference, CONCAT(sessionid, ' ' , session_title) AS session FROM ConferenceSessionsConferenceSessions
| extend session=strcat(sessionid, " ", session_title)
| project conference, session
strcat()
project
OrderingSELECT name, timestamp FROM dependencies
ORDER BY timestamp ASC
dependencies
| project name, timestamp
| sort by timestamp asc nulls last
sort
Top n by measureSELECT TOP 100 name, COUNT(*) as Count FROM dependencies
GROUP BY name
ORDER BY Count DESC
dependencies
| summarize Count = count() by name
| top 100 by Count desc
top
UnionSELECT * FROM dependencies
UNION
SELECT * FROM exceptions
union dependencies, exceptionsunion
SELECT * FROM dependencies
WHERE timestamp > ...
UNION
SELECT * FROM exceptions
WHERE timestamp > ...
dependencies
| where timestamp > ago(1d)
| union
(exceptions
| where timestamp > ago(1d))
JoinSELECT * FROM dependencies
LEFT OUTER JOIN exceptions
ON dependencies.operation_Id = exceptions.operation_Id
dependencies
| join kind = leftouter
(exceptions)
on $left.operation_Id == $right.operation_Id
join
Nested queries
Sub-query
SELECT * FROM dependencies
WHERE resultCode ==
(SELECT TOP 1 resultCode FROM dependencies
WHERE resultId = 7
ORDER BY timestamp DESC)
dependencies
| where resultCode == toscalar(
dependencies
| where resultId == 7
| top 1 by timestamp desc
| project resultCode)
toscalar
HavingSELECT COUNT(\*) FROM dependencies
GROUP BY name
HAVING COUNT(\*) > 3
dependencies
| summarize Count = count() by name
| where Count > 3
summarize
where

Kusto Query Language (KQL) – quick reference

It is for the new KQL engineer to quick reference only.

KQL Work Flow

Quick reference

Operator/FunctionDescriptionSyntax
Filter/Search/ConditionFind relevant data by filtering or searching
whereFilters on a specific predicateT | where Predicate
where contains/hasContains: Looks for any substring match
Has: Looks for a specific word (better performance)
T | where col1 contains/has "[search term]"
searchSearches all columns in the table for the value[TabularSource |] search [kind=CaseSensitivity] [in (TableSources)] SearchPredicate
takeReturns the specified number of records. Use to test a query
Notetake and limit are synonyms.
T | take NumberOfRows
caseAdds a condition statement, similar to if/then/elseif in other systems.case(predicate_1, then_1, predicate_2, then_2, predicate_3, then_3, else)
distinctProduces a table with the distinct combination of the provided columns of the input tabledistinct [ColumnName], [ColumnName]
Date/TimeOperations that use date and time functions
agoReturns the time offset relative to the time the query executes. For example, ago(1h) is one hour before the current clock’s reading.ago(a_timespan)
format_datetimeReturns data in various date formats.format_datetime(datetime , format)
binRounds all values in a timeframe and groups thembin(value,roundTo)
Create/Remove ColumnsAdd or remove columns in a table
printOutputs a single row with one or more scalar expressionsprint [ColumnName =] ScalarExpression [',' ...]
projectSelects the columns to include in the order specifiedT | project ColumnName [= Expression] [, ...]
Or
T | project [ColumnName | (ColumnName[,]) =] Expression [, ...]
project-awaySelects the columns to exclude from the outputT | project-away ColumnNameOrPattern [, ...]
project-keepSelects the columns to keep in the outputT | project-keep ColumnNameOrPattern [, ...]
project-renameRenames columns in the result outputT | project-rename new_column_name = column_name
project-reorderReorders columns in the result outputT | project-reorder Col2, Col1, Col* asc
extendCreates a calculated column and adds it to the result setT | extend [ColumnName | (ColumnName[, ...]) =] Expression [, ...]
Sort and Aggregate DatasetRestructure the data by sorting or grouping them in meaningful ways
sort operatorSort the rows of the input table by one or more columns in ascending or descending orderT | sort by expression1 [asc|desc], expression2 [asc|desc], …
topReturns the first N rows of the dataset when the dataset is sorted using byT | top numberOfRows by expression [asc|desc] [nulls first|last]
summarizeGroups the rows according to the by group columns, and calculates aggregations over each groupT | summarize [[Column =] Aggregation [, ...]] [by [Column =] GroupExpression [, ...]]
countCounts records in the input table (for example, T)
This operator is shorthand for summarize count()
T | count
joinMerges the rows of two tables to form a new table by matching values of the specified column(s) from each table. Supports a full range of join types: fullouterinnerinneruniqueleftantileftantisemileftouterleftsemirightantirightantisemirightouterrightsemiLeftTable | join [JoinParameters] ( RightTable ) on Attributes
unionTakes two or more tables and returns all their rows[T1] | union [T2], [T3], …
rangeGenerates a table with an arithmetic series of valuesrange columnName from start to stop step step
Format DataRestructure the data to output in a useful way
lookupExtends the columns of a fact table with values looked-up in a dimension tableT1 | lookup [kind = (leftouter|inner)] ( T2 ) on Attributes
mv-expandTurns dynamic arrays into rows (multi-value expansion)T | mv-expand Column
parseEvaluates a string expression and parses its value into one or more calculated columns. Use for structuring unstructured data.T | parse [kind=regex [flags=regex_flags] |simple|relaxed] Expression with * (StringConstant ColumnName [: ColumnType]) *...
make-seriesCreates series of specified aggregated values along a specified axisT | make-series [MakeSeriesParamters] [Column =] Aggregation [default = DefaultValue] [, ...] on AxisColumn from start to end step step [by [Column =] GroupExpression [, ...]]
letBinds a name to expressions that can refer to its bound value. Values can be lambda expressions to create query-defined functions as part of the query. Use let to create expressions over tables whose results look like a new table.let Name = ScalarExpression | TabularExpression | FunctionDefinitionExpression
GeneralMiscellaneous operations and function
invokeRuns the function on the table that it receives as input.T | invoke function([param1, param2])
evaluate pluginNameEvaluates query language extensions (plugins)[T |] evaluate [ evaluateParameters ] PluginName ( [PluginArg1 [, PluginArg2]... )
VisualizationOperations that display the data in a graphical format
renderRenders results as a graphical outputT | render Visualization [with (PropertyName = PropertyValue [, ...] )]

Using sp_MSforeachdb to Search for Objects Across All Databases

You are working on a project that requires migrating legacy stuffs from old environment to a new one, and requirement says upgrade business logic to latest. Unfortunately, not enough and clearly documents for you to refer. You did not even know an object where it is since there are so many databases resident in the same server, so many tables, so many views, stored procedure, user defined functions… etc. It is hard to find out the legacy business logics.

sp_MSforeachdb

The sp_MSforeachdb procedure is an undocumented procedure that allows you to run the same command against all databases. There are several ways to get creative with using this command and we will cover these in the examples below. This can be used to select data, update data and even create database objects. You can use the sp_MSforeachdb stored procedure to search for objects by their name across all databases:

EXEC sp_MSforeachdb
'USE [?];
SELECT ''?'' AS DatabaseName, name AS ObjectName
, type_desc AS ObjectType
, Type_desc as object_Desc
, Create_date
, Modify_date
FROM sys.objects
WHERE name = ''YourObjectName'';';

Replace ‘YourObjectName’ with the actual name of the object you’re searching for (table, view, stored procedure, etc.).

The type_desc column will tell you the type of the object (e.g., USER_TABLE, VIEW, SQL_STORED_PROCEDURE, etc.).

For example, find out the “tb” prefix objects

EXEC sp_MSforeachdb
'USE [?];
SELECT ''?'' AS DatabaseName
, name AS objectName
, type_desc as object_Desc
, create_date, Modify_date
FROM sys.objects
WHERE name like ''tb%'';'
go

Alternative – Loop Through Databases Using a Cursor

If sp_MSforeachdb is not available, you can use a cursor to loop through each database and search for the object:

DECLARE @DBName NVARCHAR(255);
DECLARE @SQL NVARCHAR(MAX);

DECLARE DB_Cursor CURSOR FOR
SELECT name
FROM sys.databases
WHERE state = 0;  -- Only look in online databases

OPEN DB_Cursor;
FETCH NEXT FROM DB_Cursor INTO @DBName;

WHILE @@FETCH_STATUS = 0
BEGIN
    SET @SQL = 
    'USE [' + @DBName + ']; 
     IF EXISTS (SELECT 1 FROM sys.objects WHERE name = ''YourObjectName'')
     BEGIN
         SELECT ''' + @DBName + ''' AS DatabaseName, name AS ObjectName, type_desc AS ObjectType
         FROM sys.objects
         WHERE name = ''YourObjectName'';
     END';

    EXEC sp_executesql @SQL;

    FETCH NEXT FROM DB_Cursor INTO @DBName;
END;

CLOSE DB_Cursor;
DEALLOCATE DB_Cursor;


You can modify the query to search for specific object types, such as tables or stored procedures:

Find the table

You can use the sp_MSforeachdb system stored procedure to search for the table across all databases.

EXEC sp_MSforeachdb 
'USE [?]; 
 SELECT ''?'' AS DatabaseName, name AS TableName 
 FROM sys.tables 
 WHERE name = ''YourTableName'';';

If sp_MSforeachdb is not enabled or available, you can use a cursor to loop through all databases and search for the table:

DECLARE @DBName NVARCHAR(255);
DECLARE @SQL NVARCHAR(MAX);

DECLARE DB_Cursor CURSOR FOR
SELECT name
FROM sys.databases
WHERE state = 0;  -- Only look in online databases

OPEN DB_Cursor;
FETCH NEXT FROM DB_Cursor INTO @DBName;

WHILE @@FETCH_STATUS = 0
BEGIN
    SET @SQL = 
    'USE [' + @DBName + ']; 
     IF EXISTS (SELECT 1 FROM sys.tables WHERE name = ''YourTableName'')
     BEGIN
         SELECT ''' + @DBName + ''' AS DatabaseName, name AS TableName
         FROM sys.tables
         WHERE name = ''YourTableName'';
     END';

    EXEC sp_executesql @SQL;

    FETCH NEXT FROM DB_Cursor INTO @DBName;
END;

CLOSE DB_Cursor;
DEALLOCATE DB_Cursor;

Find the View

You can use the sp_MSforeachdb system stored procedure to search for the view across all databases.

EXEC sp_MSforeachdb 
'USE [?];
SELECT ''?'' AS DatabaseName, name AS TableName
FROM sys.views
WHERE name = ''YourTableName'';';

Find the Stored Procedure

EXEC sp_MSforeachdb 
'USE [?]; 
 SELECT ''?'' AS DatabaseName, name AS ProcedureName 
 FROM sys.procedures 
 WHERE name = ''YourProcedureName'';';

Please do not hesitate to contact me if you have any questions at William . chen @ mainri.ca

(remove all space from the email account 😊)