Convert Teradata BTEQ and SQL to BigQuery

BTEQ scripts, stored procedures, and Teradata SQL parsed structurally. Converted to BigQuery SQL with native QUALIFY support. Proprietary functions, MERGE INTO, and PRIMARY INDEX logic fully translated.

Upload a BTEQ script, get converted code →
Why BigQuery

Teradata's fixed-capacity model doesn't fit modern analytics

QUALIFY preserved natively in BigQuery

BigQuery supports QUALIFY as a first-class SQL clause. Teradata's QUALIFY ROW_NUMBER(), RANK(), and DENSE_RANK() patterns transfer directly—no subquery wrapping, no CTE rewrite needed. The analytical intent stays clean and performant.

BTEQ becomes BigQuery scripting

BTEQ's .LOGON, .IF/.THEN, .GOTO control flow and embedded SQL are parsed and converted to BigQuery scripting blocks with DECLARE, SET, IF/THEN/ELSE, and LOOP. .LABEL and .QUIT logic becomes structured exception handling in BigQuery procedures.

Proprietary functions map to BigQuery equivalents

Teradata-specific functions like HASHROW, HASHBUCKET, NORMALIZE, EXPAND ON, and SAMPLE are mapped to BigQuery equivalents. BYTEINT, PERIOD, and INTERVAL data types are translated to BigQuery-native types. No proprietary runtime needed.

Parser output

BTEQ with Teradata-specific functions to BigQuery SQL

A BTEQ script using QUALIFY, SAMPLE, and MERGE INTO with Teradata-specific date arithmetic—converted to BigQuery SQL where QUALIFY is preserved and proprietary functions are mapped.

Teradata BTEQ
.LOGON tdserver/dbc,dbc;

COLLECT STATISTICS ON sales_data
  COLUMN (store_id, sale_date);

SELECT store_id, sale_date, revenue,
       product_category,
       revenue - LAG(revenue) OVER (
         PARTITION BY store_id
         ORDER BY sale_date
       ) AS revenue_change
FROM sales_data
WHERE sale_date BETWEEN DATE - 90
                     AND DATE
QUALIFY RANK() OVER (
  PARTITION BY store_id
  ORDER BY revenue DESC
) <= 5;

MERGE INTO store_summary tgt
USING (
  SELECT store_id,
         SUM(revenue) AS total_rev,
         COUNT(*) AS txn_count
  FROM sales_data
  WHERE sale_date >= DATE - 30
  GROUP BY store_id
) src
ON tgt.store_id = src.store_id
WHEN MATCHED THEN UPDATE SET
  total_revenue  = src.total_rev,
  txn_count      = src.txn_count,
  last_updated   = CURRENT_DATE
WHEN NOT MATCHED THEN INSERT VALUES (
  src.store_id, src.total_rev,
  src.txn_count, CURRENT_DATE
);

.LOGOFF;
.QUIT;
MigryX
converts
BigQuery SQL
-- BTEQ → BigQuery SQL
-- COLLECT STATISTICS: BigQuery manages
-- statistics automatically (no action needed)

SELECT store_id, sale_date, revenue,
       product_category,
       revenue - LAG(revenue) OVER (
         PARTITION BY store_id
         ORDER BY sale_date
       ) AS revenue_change
FROM `project.dataset.sales_data`
WHERE sale_date BETWEEN
  DATE_SUB(CURRENT_DATE(), INTERVAL 90 DAY)
  AND CURRENT_DATE()
QUALIFY RANK() OVER (
  PARTITION BY store_id
  ORDER BY revenue DESC
) <= 5;

MERGE INTO `project.dataset.store_summary` tgt
USING (
  SELECT store_id,
         SUM(revenue) AS total_rev,
         COUNT(*) AS txn_count
  FROM `project.dataset.sales_data`
  WHERE sale_date >= DATE_SUB(
    CURRENT_DATE(), INTERVAL 30 DAY)
  GROUP BY store_id
) src
ON tgt.store_id = src.store_id
WHEN MATCHED THEN UPDATE SET
  total_revenue  = src.total_rev,
  txn_count      = src.txn_count,
  last_updated   = CURRENT_DATE()
WHEN NOT MATCHED THEN INSERT VALUES (
  src.store_id, src.total_rev,
  src.txn_count, CURRENT_DATE()
);

BTEQ control flow removed. QUALIFY preserved natively in BigQuery. DATE arithmetic mapped to DATE_SUB with INTERVAL. Table references become fully-qualified project.dataset.table. MERGE INTO syntax preserved with minor adjustments.

Coverage

Teradata to BigQuery — artifact mapping

Teradata Component BigQuery Equivalent Notes
BTEQ scriptBigQuery scripting / procedure.LOGON/.LOGOFF removed, SQL extracted and converted
QUALIFY clauseQUALIFY (native)BigQuery supports QUALIFY natively—no rewrite
COLLECT STATISTICSAutomatic (not needed)BigQuery manages optimizer statistics internally
PRIMARY INDEXPartition + clusteringPARTITION BY date + CLUSTER BY for co-location
FastLoadbq load / BigQuery DTSBatch ingestion via CLI or Data Transfer Service
MultiLoadMERGE INTOUpsert and conditional update patterns
Stored ProcedureBigQuery procedureSQL-based procedures with scripting blocks
MacroProcedure + parametersReusable parameterized SQL blocks
SET tableSELECT DISTINCT / MERGEUnique-row enforcement via deduplication
MERGE INTOMERGE (native DML)WHEN MATCHED / NOT MATCHED fully preserved
Temporal tableTime travel + snapshotsFOR SYSTEM_TIME AS OF for historical queries
TPumpBigQuery streaming insertStorage Write API for near-real-time ingestion
Validation

Every conversion validated to row-level parity

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

See how Data Matching works →
2,800
BTEQ scripts modernized
6X
Performance gain
$5.1M
Savings over 3 years
900
QUALIFY clauses preserved

Retail Enterprise: Teradata to BigQuery in 12 Months

2,800 BTEQ scripts converted to BigQuery SQL. 900 QUALIFY clauses preserved natively without subquery wrapping. FastLoad and MultiLoad jobs replaced with bq load and BigQuery MERGE. PRIMARY INDEX strategies mapped to partitioning and clustering. 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, BigQuery SQL code, and a validation report.

Book a Live Demo → hello@migryx.com