Convert Teradata BTEQ and SQL to PySpark on Databricks

BTEQ scripts, FastLoad jobs, stored procedures, and Teradata SQL parsed structurally. Converted to PySpark notebooks on Databricks with Delta Lake. QUALIFY, MERGE INTO, and PRIMARY INDEX logic fully translated.

Upload a BTEQ script, get converted code →
Why Databricks

Teradata wasn't built for open lakehouse economics

BTEQ scripts become PySpark notebooks

BTEQ's .LOGON, .IF/.THEN, .GOTO control flow and embedded SQL are parsed and converted to idiomatic PySpark notebooks. .LABEL and .QUIT logic becomes structured Python error handling. No more proprietary CLI scripting.

QUALIFY and window functions translate cleanly

Teradata's QUALIFY clause with ROW_NUMBER(), RANK(), and DENSE_RANK() is converted to PySpark Window functions with a .filter() step. The analytical logic is preserved exactly—no manual rewrite needed.

FastLoad and MultiLoad become Auto Loader and COPY INTO

Teradata's proprietary bulk-loading utilities—FastLoad, MultiLoad, FastExport, TPump—are replaced by Databricks Auto Loader for streaming ingestion and COPY INTO for batch loads. No Teradata channel drivers required.

Parser output

BTEQ with QUALIFY and MERGE to PySpark on Delta

A BTEQ script using QUALIFY ROW_NUMBER() for deduplication and MERGE INTO for upserts—converted to PySpark Window functions and Delta Lake merge operations.

Teradata BTEQ
.LOGON tdserver/dbc,dbc;

COLLECT STATISTICS ON customer_orders
  COLUMN (customer_id);

CREATE VOLATILE TABLE latest_orders AS (
  SELECT customer_id, order_date, amount,
         order_status
  FROM customer_orders
  QUALIFY ROW_NUMBER() OVER (
    PARTITION BY customer_id
    ORDER BY order_date DESC
  ) = 1
) WITH DATA ON COMMIT PRESERVE ROWS;

MERGE INTO customer_summary tgt
USING latest_orders src
ON tgt.customer_id = src.customer_id
WHEN MATCHED THEN UPDATE SET
  last_order_date = src.order_date,
  last_amount     = src.amount,
  status          = src.order_status
WHEN NOT MATCHED THEN INSERT VALUES (
  src.customer_id, src.order_date,
  src.amount, src.order_status
);

.LOGOFF;
.QUIT;
MigryX
converts
PySpark on Databricks
# BTEQ → PySpark on Databricks
from pyspark.sql import functions as F
from pyspark.sql.window import Window
from delta.tables import DeltaTable

spark.sql("ANALYZE TABLE customer_orders
  COMPUTE STATISTICS FOR COLUMNS customer_id")

w = Window.partitionBy("customer_id") \
          .orderBy(F.col("order_date").desc())

latest_orders = (
    spark.read.table("customer_orders")
    .withColumn("_rn", F.row_number().over(w))
    .filter(F.col("_rn") == 1)
    .drop("_rn")
)

tgt = DeltaTable.forName(spark, "customer_summary")
tgt.alias("tgt").merge(
    latest_orders.alias("src"),
    "tgt.customer_id = src.customer_id"
).whenMatchedUpdate(set={
    "last_order_date": "src.order_date",
    "last_amount":     "src.amount",
    "status":          "src.order_status"
}).whenNotMatchedInsertAll().execute()

BTEQ control flow removed. QUALIFY ROW_NUMBER() becomes Window + filter. COLLECT STATISTICS becomes ANALYZE TABLE. MERGE INTO becomes Delta Lake merge. Volatile table becomes DataFrame.

Coverage

Teradata to Databricks — artifact mapping

Teradata Component Databricks Equivalent Notes
BTEQ scriptPySpark notebook.LOGON/.LOGOFF removed, SQL extracted and converted
QUALIFY clauseWindow function + .filter()ROW_NUMBER, RANK, DENSE_RANK preserved
COLLECT STATISTICSANALYZE TABLEColumn-level statistics for query optimization
PRIMARY INDEXDelta ZORDER BYData co-location strategy mapped
FastLoadAuto Loader / COPY INTOStreaming or batch ingestion from files
MultiLoadMERGE INTO DeltaUpsert and conditional update patterns
Stored ProcedurePython function / notebookControl flow and cursor logic translated
MacroParameterized notebookParameters via widgets, reusable execution
SET table.dropDuplicates()Unique-row enforcement at write time
MERGE INTODelta MERGEWHEN MATCHED / NOT MATCHED fully preserved
Temporal tableDelta time travelPERIOD columns become versioned Delta history
TPumpStructured StreamingNear-real-time continuous ingestion
Validation

Every conversion validated to row-level parity

Data Matching compares Teradata output against Databricks output—row by row, column by column. In the case study below, all BTEQ pipelines were validated with full production backtesting across 3,500 scripts.

See how Data Matching works →
3,500
BTEQ scripts modernized
5X
Performance gain
$6.2M
Savings over 3 years
1,200
QUALIFY clauses rewritten

Telecom Provider: Teradata to Databricks in 14 Months

3,500 BTEQ scripts converted to PySpark on Databricks. 1,200 QUALIFY clauses rewritten to Window functions. FastLoad and MultiLoad jobs replaced with Auto Loader and Delta MERGE. PRIMARY INDEX strategies mapped to ZORDER. Teradata appliance decommissioned within 90 days.

Read the full case study →

See it on your own Teradata scripts

Upload a BTEQ script or Teradata SQL file. Get parsed lineage, PySpark code for Databricks, and a validation report.

Book a Live Demo → hello@migryx.com