Option 1 — Notebook widgets (simple & reliable)
Use a Databricks widget to pass the environment (e.g., via Jobs/Workflows parameter), then build the table name dynamically.
# Databricks notebook
dbutils.widgets.dropdown("env", "dev", ["dev", "prod"], "Environment")
env = dbutils.widgets.get("env")
# Map env → Snowflake database
db_map = {"dev": "VD_DWH", "prod": "VP_DWH"}
source_db = db_map.get(env, "VD_DWH") # default to dev
source_table_fqn = f"{source_db}.SALES.SALES_DETAIL"
# Snowflake connection options (store secrets in Databricks Secrets)
sfOptions = {
"sfUrl": dbutils.secrets.get("scope", "sfUrl"),
"sfUser": dbutils.secrets.get("scope", "sfUser"),
"sfPassword": dbutils.secrets.get("scope", "sfPassword"),
"sfWarehouse": dbutils.secrets.get("scope", "sfWarehouse"),
"sfRole": dbutils.secrets.get("scope", "sfRole"),
}
# Read from Snowflake table into Spark DataFrame
df = (spark.read
.format("snowflake")
.options(**sfOptions)
.option("dbtable", source_table_fqn)
.load())
# Do your transforms, then write to Delta/UC
df.write.mode("overwrite").saveAsTable("lakehouse.sales_detail")
``
Option 2 — Jobs/Workflows parameters (no widgets in code)
If you’re scheduling via Databricks Jobs (or your orchestrator like ADF/Airflow), pass env as a parameter and read it with dbutils.widgets.get. You can also pass the database name directly as a parameter to avoid mapping.
Option 3 — Configuration-driven (robust for many tables)
Centralize environment settings (e.g., in a UC Volume/Delta table or notebook-scoped JSON) and look them up
import json
config_json = """
{
"dev": {"source_db": "VD_DWH"},
"prod": {"source_db": "VP_DWH"}
}
"""
cfg = json.loads(config_json)
env = dbutils.widgets.get("env") # or default 'dev'
source_db = cfg[env]["source_db"]
source_table_fqn = f"{source_db}.SALES.SALES_DETAIL"
# ... proceed to read from Snowflake