You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Microsoft Fabric Spark SQL supports 4-part naming (workspace.lakehouse.schema.table) for cross-workspace queries and writes in schema-enabled lakehouses. This allows a single dbt project to read from and write to multiple Fabric workspaces without requiring OneLake shortcuts.
Currently our adapter renders relations as 3-part names (lakehouse.schema.table), limiting operations to the current workspace.
Confirmed working (tested 2026-05-17 via ad-hoc Livy statements):
Statement
4-part support
SELECT * FROM \ws`.`lh`.`schema`.`table``
Yes
INSERT INTO \ws`.`lh`.`schema`.`table``
Yes
CREATE TABLE \ws`.`lh`.`schema`.`table` AS SELECT ...`
Yes
MERGE INTO \ws`.`lh`.`schema`.`table``
Yes
CREATE OR REPLACE VIEW \ws`.`lh`.`schema`.`view``
Yes
CREATE OR REPLACE MATERIALIZED LAKE VIEW ...
Untested (REST API path)
DROP TABLE/VIEW IF EXISTS \ws`.`lh`.`schema`.`obj``
Yes
Requirements
The session's default lakehouse must be schema-enabled (or unset)
User must have permissions on the target workspace/lakehouse
Non-schema lakehouses use 3-part cross-workspace names (workspace.lakehouse.table) — we don't need to support this since our adapter requires schema-enabled lakehouses
This ensures this (used in incremental, snapshot, etc.) automatically carries the workspace. No per-materialization changes needed for the common path.
4. Handle incorporate() for workspace propagation
Override incorporate() (or ensure from_dict round-trips the workspace field) so that macros using target_relation.incorporate(...) preserve the workspace.
5. Update _build_spark_relation_list and catalog queries
We already extract the workspace from the 3-part namespace in _build_spark_relation_list and store it as catalog. Map this to the workspace field instead. Update SHOW TABLE EXTENDED queries to optionally use 4-part names when listing relations in other workspaces.
6. Validation
Reject workspace_name when schema-enabled mode is off (if we ever support non-schema mode)
Consider a parse-time warning/error if workspace_name targets the current workspace (redundant)
7. Update materializations (minimal)
Thanks to create_from() handling the workspace via this, most materializations work without changes. Verify:
Staging tables in snapshot — forward target_relation.workspace to tmp_relation.
8. ensure_database_exists / CREATE DATABASE IF NOT EXISTS
The existing ensure_database_exists macro should forward the workspace so that CREATE DATABASE IF NOT EXISTS \ws`.`lh`.`schema`` works cross-workspace.
9. Tests
Unit tests: relation rendering with/without workspace
Integration tests: cross-workspace CTAS, MERGE, view creation (requires a second workspace in CI)
10. Documentation
Add docs page for cross-workspace models
Document the workspace_name config option
Note that this only works with schema-enabled lakehouses
Out of scope
Cross-workspace materialized lake views via REST API (the MLV REST API resolves lakehouse IDs against the profile workspace — a separate concern)
Non-schema lakehouse support (3-part cross-workspace names)
Context
Microsoft Fabric Spark SQL supports 4-part naming (
workspace.lakehouse.schema.table) for cross-workspace queries and writes in schema-enabled lakehouses. This allows a single dbt project to read from and write to multiple Fabric workspaces without requiring OneLake shortcuts.Currently our adapter renders relations as 3-part names (
lakehouse.schema.table), limiting operations to the current workspace.Confirmed working (tested 2026-05-17 via ad-hoc Livy statements):
SELECT * FROM \ws`.`lh`.`schema`.`table``INSERT INTO \ws`.`lh`.`schema`.`table``CREATE TABLE \ws`.`lh`.`schema`.`table` AS SELECT ...`MERGE INTO \ws`.`lh`.`schema`.`table``CREATE OR REPLACE VIEW \ws`.`lh`.`schema`.`view``CREATE OR REPLACE MATERIALIZED LAKE VIEW ...DROP TABLE/VIEW IF EXISTS \ws`.`lh`.`schema`.`obj``Requirements
workspace.lakehouse.table) — we don't need to support this since our adapter requires schema-enabled lakehousesPrior art
Microsoft's upstream
dbt-fabricsparkimplemented this in:Design
User interface
Users set
workspace_namein their model config to target a different workspace:{{ config( materialized='table', workspace_name='other-workspace', database='other-lakehouse', schema='my_schema' ) }} SELECT * FROM {{ ref('local_model') }}When
workspace_nameis not set, behavior is unchanged (3-part names within the current workspace).Implementation plan
1. Add
workspacefield toFabricSparkRelationThe field is render-only — it does NOT participate in cache identity (the cache key remains
database.schema.identifier).2. Override
render()to prepend workspaceThe workspace prefix is only emitted when
include_policy.databaseis True — temp tables and CTEs that use.include(database=False)remain unqualified.3. Override
create_from()to pullworkspace_namefrom model configThis ensures
this(used in incremental, snapshot, etc.) automatically carries the workspace. No per-materialization changes needed for the common path.4. Handle
incorporate()for workspace propagationOverride
incorporate()(or ensurefrom_dictround-trips theworkspacefield) so that macros usingtarget_relation.incorporate(...)preserve the workspace.5. Update
_build_spark_relation_listand catalog queriesWe already extract the workspace from the 3-part namespace in
_build_spark_relation_listand store it ascatalog. Map this to theworkspacefield instead. UpdateSHOW TABLE EXTENDEDqueries to optionally use 4-part names when listing relations in other workspaces.6. Validation
workspace_namewhen schema-enabled mode is off (if we ever support non-schema mode)7. Update materializations (minimal)
Thanks to
create_from()handling the workspace viathis, most materializations work without changes. Verify:table.sql— usesthis.incorporate(type='table')→ workspace preserved ✓incremental.sql— usesthis.incorporate(type='table')→ workspace preserved ✓materialized_view.sql— usesthis.incorporate(type=...)→ workspace preserved ✓snapshot.sql— usesget_or_create_relation()which doesn't carry workspace. Need to re-incorporate workspace ontotarget_relationafterget_or_create_relation(same fix as upstream PR Add FabricSpark integration tests for dbt-profiler package #182).target_relation.workspacetotmp_relation.8.
ensure_database_exists/CREATE DATABASE IF NOT EXISTSThe existing
ensure_database_existsmacro should forward the workspace so thatCREATE DATABASE IF NOT EXISTS \ws`.`lh`.`schema`` works cross-workspace.9. Tests
10. Documentation
workspace_nameconfig optionOut of scope
References