SnowConvert AI - Teradata - BTEQ¶
Translation references to convert Teradata BTEQ files to Snowflake SQL
Description¶
Note
Some parts in the output code are omitted for clarity reasons.
Basic Teradata Query (BTEQ) is a general-purpose, command-based program that enables users on a workstation to communicate with one or more Teradata Database systems and to format reports for both print and screen output.
For more information, see the Teradata BTEQ Reference.
Sample Source Patterns¶
1. Basic BTEQ Example¶
The BTEQ content is relocated within an EXECUTE IMMEDIATE block to transfer the BTEQ script functionality to Snowflake SQL executable code.
All the DML and DDL statements inside BTEQ scripts are supported by SnowConvert AI and successfully translated to Snowflake SQL. The commands that do not have support yet, or do not have support at all, are being marked with a warning message and commented out.
Teradata BTEQ¶
Snowflake SQL¶
2. Bash Variable Placeholders Example¶
SnowConvert AI supports the migration of BTEQ code with Bash Variable Placeholders used for shell scripts. These placeholders are migrated to Snowflake CLI template syntax (<%VAR%>) and SSC-FDM-TD0003 is added to the code. Please consider the following when migrating code with these placeholders:
- SnowConvert AI does not support the migration of shell scripts. To migrate the BTEQ code, isolate it in a BTEQ file and supply it as input for the tool.
- Snowflake CLI is required to execute the migrated code. Variables are passed via
-Dflags:snow sql -f script.sql -D "VAR=value". For more information, see SSC-FDM-TD0003.
Teradata BTEQ¶
Snowflake SQL¶
3. .IF, .GOTO, and .LABEL (Snowflake Scripting)¶
When the BTEQ script target is Snowflake Scripting (SnowScript), SnowConvert AI translates .IF, .GOTO, and .LABEL by modeling jumps as nested procedure calls and early returns inside a single EXECUTE IMMEDIATE … `` block. Snowflake does not provide BTEQ-style goto/label semantics.
| BTEQ construct | Snowflake Scripting approach |
|---|---|
| Script body with labels | Wrapped in EXECUTE IMMEDIATE … `` with DECLARE, nested procedures, and a top-level BEGIN … END |
.LABEL name | Section name becomes a nested procedure; handoffs use CALL name(); |
.GOTO name | CALL name(); followed by RETURN 'PROCESS FINISHED'; |
.IF ERRORCODE … | IF (STATUS_OBJECT['SQLCODE'] …) using a status object updated in EXCEPTION handlers |
.IF ACTIVITYCOUNT … | IF on row count from TABLE(RESULT_SCAN(LAST_QUERY_ID())) |
| Error/status tracking | STATUS_OBJECT holds status fields; generated SQL may include SSC-FDM-TD0013 (Snowflake SQLCODE is not the same as Teradata ERRORCODE) |
Note
To produce output in this form, set the Teradata/BTEQ script output to Snowflake Scripting (for example -- Additional Params: -q SnowScript in the samples below). Option names vary by interface; see the SnowConvert AI user guide for your product version.
The following example shows .IF ERRORCODE with .GOTO and .LABEL. Teradata BTEQ often branches on ERRORCODE after DDL and jumps to a labeled cleanup or next step.
Teradata BTEQ¶
Snowflake SQL¶
After each statement that can set SQL state, the generated IF checks STATUS_OBJECT['SQLCODE']. On error, the script calls the target label procedure and returns from the current procedure so later statements in that section do not run. On success, it calls the next section’s procedure to continue the original linear flow.
The next example shows .IF ActivityCount = 0 THEN .GOTO …, expressed in Snowflake Scripting using the last query id and RESULT_SCAN.
Teradata BTEQ¶
Snowflake SQL¶
If activity count is zero, the generated script jumps to the label section with CALL Continue_No_Rejects_00() and RETURN 'PROCESS FINISHED', skipping DROP TABLE DROPTEDTABLE1. Otherwise it runs DROP TABLE, then calls the label procedure to run SELECT A FROM AUDITORIA.
Data Import (.IMPORT)¶
SnowConvert AI translates the BTEQ .IMPORT block (.IMPORT VARTEXT|REPORT|FILE paired with .REPEAT and a USING clause) into a Snowflake COPY INTO statement or a staging-table + bulk DML pipeline, depending on the inner DML. A CREATE TEMPORARY STAGE and PUT are emitted at the top of the script so the file can be uploaded with the Snowflake CLI (snow sql -f script.sql).
.IMPORT form | Inner DML | Snowflake output |
|---|---|---|
VARTEXT | INSERT | COPY INTO target |
VARTEXT | INSERT + .REPEAT n | Staging table with sc_seq + sequenced COPY INTO + INSERT … ORDER BY sc_seq LIMIT n + DROP TABLE |
VARTEXT | UPDATE, DELETE, MERGE, SELECT | Staging table built from the USING columns + bulk DML aliased SRC / TGT + DROP TABLE |
VARTEXT | EXEC / CALL | Temporary FILE FORMAT + LET … CURSOR FOR + FOR rec IN cursor DO … CALL proc(:col); END FOR |
REPORT / FILE (no format) | INSERT | COPY INTO target with RTRIM(SUBSTRING($1, start, width)) per column |
REPORT / FILE | UPDATE, DELETE, MERGE, SELECT | Same staging pattern as VARTEXT, with RTRIM(SUBSTRING(...)) extraction in the load step |
1. VARTEXT Format - INSERT (COPY INTO)¶
A single INSERT … VALUES (:host, …) over a delimited file is translated to a single COPY INTO target whose inner SELECT uses positional $N references to pick fields from the staged file. :host references that map to a USING column are rewritten to their corresponding position; literals and other expressions are kept as-is.
Teradata BTEQ¶
Snowflake SQL¶
If the VALUES list reorders the USING columns or interleaves literals (for example VALUES (:col2, :col1, 'X')), the COPY INTO source SELECT mirrors that order so each output position keeps its original semantics.
2. VARTEXT Format - INSERT with .REPEAT n (Sequenced Staging)¶
When .REPEAT has a numeric limit (.REPEAT 100), BTEQ processes exactly that many rows. The translation uses a temporary staging table that captures the file row order through METADATA$FILE_ROW_NUMBER (column sc_seq), and then issues an INSERT … SELECT … ORDER BY sc_seq LIMIT n to reproduce the bounded behavior. The staging table is dropped after the insert.
Teradata BTEQ¶
Snowflake SQL¶
3. VARTEXT Format - UPDATE / DELETE / MERGE / SELECT (Staging + Bulk DML)¶
When the inner DML is UPDATE, DELETE, MERGE, or SELECT, the row-by-row Teradata pipeline is collapsed into a single bulk statement. The schema of the staging table is built from the USING clause (column names and CHAR / VARCHAR types are taken verbatim). The DML body is rewritten so that every :host becomes SRC.<col> and the target table is aliased TGT; the resulting statement runs once over the whole loaded file.
Teradata BTEQ¶
Snowflake SQL¶
The same staging pattern is used for DELETE (emits USING sc_import_staging SRC), MERGE (replaces the source (SELECT :host AS col …) s derived table with sc_import_staging SRC, keeping the original source alias when present), and SELECT (appends , sc_import_staging SRC to the FROM clause).
4. VARTEXT Format - EXEC / CALL (Cursor Loop)¶
When the inner statement is EXEC or CALL, the load is row-driven by design — each call invokes a procedure with one row’s values. SnowConvert AI emits a temporary FILE FORMAT, declares a Snowflake Scripting CURSOR whose SELECT aliases each $N to the corresponding USING column name, and iterates with FOR rec IN sc_cursor DO … END FOR. Because Snowflake’s CALL cannot accept rec.colN directly as an argument, each host-parameter argument is captured into a LET local and passed through :bind syntax. Literal arguments pass through unchanged.
Teradata BTEQ¶
Snowflake SQL¶
5. REPORT / FILE Format (Fixed-Width)¶
.IMPORT REPORT (and .IMPORT FILE with no format keyword) reads files as fixed-width records — each column occupies a fixed number of bytes given by the CHAR/VARCHAR width in the USING clause. The translation forces the entire input line into $1 by setting FIELD_DELIMITER = '\x7f' (a delimiter that does not appear in normal text) and extracts each field with RTRIM(SUBSTRING($1, start, width)). The RTRIM matches BTEQ CHAR-equality semantics (trailing-space-insensitive) so that downstream WHERE, JOIN, and MERGE-ON predicates keep working against trimmed Snowflake VARCHAR values.
Teradata BTEQ¶
Snowflake SQL¶
UPDATE / DELETE / MERGE / SELECT and EXEC / CALL paired with .IMPORT REPORT follow the same pipelines documented above for VARTEXT, with the load step replaced by the RTRIM(SUBSTRING(...)) extraction shown here.
Unsupported .IMPORT Cases¶
Cases that cannot be reliably translated emit SSC-EWI-TD0094 on the .IMPORT line with a case-specific reason. The trailing .REPEAT / USING / DML body is preserved in the output, commented out under SSC-EWI-0073, so the user can still see the original code and rewrite it manually. No CREATE TEMPORARY STAGE, PUT, or COPY INTO is emitted for the unsupported file. The cases are:
.IMPORT DATA— Teradata’s binary client format has no Snowflake equivalent..IMPORT INDICDATA— Teradata’s binary indicator-bytes format..IMPORT DDNAME = …— z/OS JCL DD card reference.- Dynamic
USINGclause (column name templated with a bash variable, e.g.USING (${COL_NAME} VARCHAR(10))) — the layout is not known at conversion time.
When .IMPORT … FILE = ${VAR} references a file path that is a single bash variable, SSC-EWI-TD0096 is added to the COPY INTO stage reference because the basename cannot be inferred. When the directory portion is variable but the filename is a literal (FILE = ${DIR}/data.csv), the basename is known and no EWI is emitted.
Data Export (.EXPORT)¶
SnowConvert AI translates the BTEQ .EXPORT block (.EXPORT REPORT|DATA|FILE= paired with a SELECT and terminated by .EXPORT RESET) into Snowflake’s unload-form COPY INTO @stage followed by a GET that downloads the file with the Snowflake CLI (snow sql -f script.sql). A CREATE TEMPORARY STAGE is emitted once at the top of the script and shared across every .EXPORT block.
.EXPORT form | FIELD_DELIMITER | HEADER | Notes |
|---|---|---|---|
REPORT FILE= | '|' | TRUE | Default for an explicit REPORT keyword. |
FILE= (no format) | '|' | TRUE | .EXPORT FILE= without a format keyword defaults to REPORT. |
DATA FILE= | '|' | FALSE | Teradata binary format is rendered as Snowflake CSV without headers. |
… , LIMIT = n | (as above) | (as above) | The bound SELECT is wrapped with LIMIT n. |
.SET SEPARATOR 'x' + REPORT | 'x' | TRUE | The active .SET SEPARATOR value overrides the default delimiter. |
| Single computed column (concatenation, function call, etc.) | NONE | FALSE | The expression already produces the entire output line, so no extra delimiter or header is inserted. |
.EXPORT RESET | — | — | Dropped from the output (no Snowflake equivalent). |
PUT and GET cannot run inside Snowflake Scripting blocks, so the GET is emitted at the top level after the EXECUTE IMMEDIATE block and is annotated with SSC-FDM-TD0038.
1. .EXPORT REPORT FILE= (explicit REPORT)¶
A multi-column SELECT becomes a COPY INTO @sc_export_stage/<file> with the default pipe delimiter and a header row.
Teradata BTEQ¶
Snowflake SQL¶
2. .EXPORT FILE= (no format keyword)¶
When no format keyword is present, BTEQ defaults to REPORT. The conversion is identical to the explicit REPORT case.
Teradata BTEQ¶
Snowflake SQL¶
3. .EXPORT DATA FILE= (binary → CSV)¶
Teradata’s binary DATA format has no Snowflake equivalent. The conversion writes the staged file as CSV without a header row.
Teradata BTEQ¶
Snowflake SQL¶
4. .SET SEPARATOR overrides FIELD_DELIMITER¶
A .SET SEPARATOR 'x' statement before an .EXPORT REPORT block sets the active separator for every subsequent .EXPORT until another .SET SEPARATOR (session-sticky behavior). The conversion uses the captured separator as the FIELD_DELIMITER and drops the .SET SEPARATOR statement from the output.
Teradata BTEQ¶
Snowflake SQL¶
5. Single computed column (FIELD_DELIMITER = NONE)¶
When the bound SELECT projects exactly one computed expression — typically a string concatenation or function call — the expression already produces the entire output line. The conversion emits FIELD_DELIMITER = NONE and HEADER = FALSE so Snowflake does not insert an extra delimiter or column-name header. The output is byte-identical to BTEQ’s REPORT for this shape.
Teradata BTEQ¶
Snowflake SQL¶
6. BTEQ output-formatting commands (.SET WIDTH, .SET TITLEDASHES, …)¶
BTEQ output-formatting commands (.SET WIDTH, .SET TITLEDASHES, .SET TITLES, .SET SIDETITLES, .SET RTITLE) commonly surround real .EXPORT blocks in customer scripts. They have no Snowflake equivalent and are commented out in the output under SSC-FDM-TD0100 so the user can audit what was removed.
Unsupported .EXPORT Cases¶
Cases that cannot be reliably translated emit SSC-EWI-TD0099 on the .EXPORT line with the variant token (INDICDATA, DIF, or DDNAME). The bound SELECT is preserved and no CREATE TEMPORARY STAGE, COPY INTO, or GET is emitted for the unsupported export. The cases are:
.EXPORT INDICDATA— Teradata’s binary indicator-bytes format..EXPORT DIF— Legacy Data Interchange Format (spreadsheet-oriented)..EXPORT … DDNAME = …— z/OS JCL DD card reference (mainframe-only).
File Inclusion (.RUN FILE)¶
SnowConvert AI translates the BTEQ .RUN FILE = <path> command into Snowflake’s EXECUTE IMMEDIATE FROM @<stage>/<file>, which loads and runs a SQL file from a Snowflake stage in the same session. A CREATE STAGE IF NOT EXISTS sc_run_stage and a PUT are emitted at the top of the converted parent script so that the referenced file is uploaded to the stage with the Snowflake CLI (snow sql -f script.sql) before the parent’s EXECUTE IMMEDIATE FROM runs. The referenced child script is also converted in the same migration run; the EXECUTE IMMEDIATE FROM invocation points at the converted output (e.g. child.bteq → child_BTEQ.sql).
.RUN form | Snowflake output | Marker |
|---|---|---|
.RUN FILE = child.bteq (target present in input) | CREATE STAGE + PUT + EXECUTE IMMEDIATE FROM @sc_run_stage/child_BTEQ.sql | SSC-FDM-TD0048 |
.RUN FILE = $LOGON_ID (logon credentials) | .RUN line dropped from execution | SSC-FDM-TD0049 |
.RUN FILE = child.bteq (child also issues .RUN) | Same as resolved, plus chain warning | SSC-FDM-TD0050 |
.RUN FILE = script.sql, SKIP = n | Commented out, no stage/PUT | SSC-EWI-TD0100 |
.RUN FILE = X paired with .EXPORT FILE = X (checkpoint) | Commented out, no stage/PUT | SSC-EWI-TD0101 |
.RUN FILE = missing.sql (file absent from input or unresolvable variable) | Commented out, no stage/PUT | SSC-EWI-TD0103 |
PUT cannot run inside Snowflake Scripting blocks, so the PUT is emitted at the top level before the parent’s EXECUTE IMMEDIATE block and is annotated with SSC-FDM-TD0038.
1. Resolved .RUN FILE = <child> (target present in input)¶
The happy path: the referenced file is found in the migration input tree (matched by basename). SnowConvert AI emits the stage + PUT prelude and rewrites the .RUN line to EXECUTE IMMEDIATE FROM @sc_run_stage/<basename>_BTEQ.sql. The conversion supports .bteq, .btq, and .sql source extensions; the converted output uses the _BTEQ.sql suffix (consistent with the rest of SnowConvert AI’s BTEQ-target naming convention).
Teradata BTEQ¶
Snowflake SQL¶
2. Logon-credentials .RUN FILE (Snowflake CLI handles auth)¶
Some BTEQ scripts source a credential file before connecting (.RUN FILE = $LOGON_ID, .RUN FILE = ${LOGIN_SCRIPT}, etc.). Snowflake configures authentication outside SQL via snow connection, so the .RUN line has no Snowflake equivalent and is dropped from the executable output under SSC-FDM-TD0049.
Teradata BTEQ¶
Snowflake SQL¶
3. Chained .RUN (child also issues .RUN)¶
When a .RUN target itself contains .RUN FILE commands, BTEQ produces a flat chain; Snowflake’s EXECUTE IMMEDIATE FROM produces nested execution instead. The data end state matches, but transaction scope and error propagation differ. SnowConvert AI flags the parent with SSC-FDM-TD0050 so the reviewer can confirm the nested behaviour is acceptable. The conversion still produces the resolved-shape output (stage + PUT + EXECUTE IMMEDIATE FROM).
Teradata BTEQ¶
middle_chain.bteq itself contains .RUN FILE = leaf_chain.bteq.
Snowflake SQL¶
4. .RUN … SKIP = n (no Snowflake equivalent)¶
EXECUTE IMMEDIATE FROM loads the entire stage file as a single SQL unit and offers no way to skip leading records. The .RUN line is commented out under SSC-EWI-TD0100; no stage or PUT is emitted.
Teradata BTEQ¶
Snowflake SQL¶
5. .RUN reading a sibling .EXPORT (checkpoint round-trip)¶
EXECUTE IMMEDIATE FROM reads from the stage copy of the file uploaded with PUT before the script started. A write performed by .EXPORT earlier in the same session is invisible to a subsequent .RUN of the same path. SnowConvert AI detects the path collision and emits SSC-EWI-TD0101 on the .RUN; the unrelated .EXPORT converts on its own.
Teradata BTEQ¶
Snowflake SQL¶
Unsupported .RUN Cases¶
Cases that cannot be reliably translated emit SSC-EWI-TD0103 on the .RUN line. The line is commented out and no CREATE STAGE or PUT is emitted. The cases are:
.RUN FILE = <name>where the target file is not present in the migration input tree..RUN FILE = $VAR/${VAR}/<% VAR %>where the path contains a substitution variable SnowConvert AI cannot resolve (logon-shaped variables are intercepted by SSC-FDM-TD0049 instead)..RUN FILE = ''— empty filename.
Known Issues¶
- There may be BTEQ commands that do not have an equivalent in Snowflake SQL
Since BTEQ is a command-based program, there may be some commands in your input code that do not have a hundred percent functional equivalence in Snowflake SQL. Those particular cases are identified, marked with warnings in the output code, and documented in the further pages.
Related EWIs ¶
- SSC-EWI-0073: Pending Functional Equivalence Review.
- SSC-FDM-TD0003: Bash variable found, Snowflake CLI is required to run this script.
- SSC-FDM-TD0013: The Snowflake error code mismatches the original Teradata error code.
- SSC-EWI-TD0094: The IMPORT command was not converted.
- SSC-EWI-TD0096: COPY INTO requires an explicit target file name.
- SSC-EWI-TD0099: Pending SnowConvert AI translation for the .EXPORT command variant.
- SSC-EWI-TD0100: .RUN SKIP= not supported.
- SSC-EWI-TD0101: .RUN checkpoint file not supported.
- SSC-EWI-TD0103: .RUN file not found in source.
- SSC-FDM-TD0038: PUT/GET command requires execution through Snowflake CLI.
- SSC-FDM-TD0048: .RUN FILE converted to EXECUTE IMMEDIATE FROM.
- SSC-FDM-TD0049: Logon credentials not required when running through Snowflake CLI.
- SSC-FDM-TD0050: .RUN chaining detected.
- SSC-FDM-TD0100: BTEQ output-formatting setting has no Snowflake equivalent.