Translation reference to convert INDEX statement to Snowflake
Warning
Currently, Create Index statement is not being converted but it is being parsed. Also, if your source code has Create index statements, these are going to be accounted for in the Assessment Report.
CREATEINDEX(col1, col2, col3)ORDERBYVALUES(col2)ON table1;CREATEINDEX my_index_name ON my_table (column1, column2);
Note
Due to architectural reasons, Snowflake does not support indexes so, SnowConvert AI will remove all the code related to the creation of indexes. Snowflake automatically creates micro-partitions for every table that help speed up the performance of DML operations, the user does not have to worry about creating or managing these micro-partitions.
Usually, this is enough to have a very good query performance however, there are ways to improve it by creating data clustering keys. Snowflake’s official page provides more information about micro-partitions and data clustering.
In SnowConvert AI, Teradata Join Indexes are transformed into Snowflake Dynamic Tables. To properly configure Dynamic Tables, two essential parameters must be defined: TARGET_LAG and WAREHOUSE. If these parameters are left unspecified in the configuration options, SnowConvert AI will default to preassigned values during the conversion, as demonstrated in the example below.
The WITH properties associated with the CREATE SCHEMA statement in Teradata are not supported in Snowflake, as there is no equivalent functionality available.
CREATEVIEW view1 (someTable.col1, someTable.col2)AS locking rowforaccessSELECT
my_table.col1, my_table.col2
FROM table1 AS my_table
WHERE my_table.col1 ='SpecificValue'UNIONALLSELECT other_table.col2
FROM table2 AS other_table
WHERE my_table.col2 = other_table.col2
The custom schema is specified in the comment section before the specification of the view, with an XML tag named “sc-view” that contains only the value of the schema and the view name separated with a period ‘.’ as shown below: <sc-view>SCHEMANAME.VIEWNAME</sc-view>
The custom schema will be used as a view qualifier, and then the name of the view and all the objects referred to in the FROM queries and inner queries will be using that custom schema. Therefore could be several views with the same name, but with different custom tags. Example: two views with the same name, will take the custom schema tag information to perform the translation.
/*<sc-view>RMSviews.EMPLOYEEB</sc-view>*/REPLACEVIEW EMPLOYEEB ASSELECT*FROM EMPLOYEE
WHERE AREA ="AREAB";/*<sc-view>Views.EMPLOYEEB</sc-view>*/REPLACEVIEW EMPLOYEEB ASSELECT*FROM EMPLOYEE
WHERE AREA ="AREAB";
The transformation for Snowflake will vary depending on the customized schema name MySchema, customized database name MyDatabase or not selecting a customized database or schema in the conversion settings.
/*<sc-view>RMSviews.EMPLOYEEB</sc-view>*/--** SSC-FDM-0007 - MISSING DEPENDENT OBJECT "EMPLOYEE" **CREATEORREPLACEVIEW RMSviews.EMPLOYEEB
COMMENT='{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"teradata"}}'ASSELECT*FROM
RMSviews.EMPLOYEE
WHERE AREA ="AREAB";/*<sc-view>Views.EMPLOYEEB</sc-view>*/--** SSC-FDM-0007 - MISSING DEPENDENT OBJECT "EMPLOYEE" **--** SSC-FDM-0019 - SEMANTIC INFORMATION COULD NOT BE LOADED FOR Views.EMPLOYEEB. CHECK IF THE NAME IS INVALID OR DUPLICATED. **CREATEORREPLACEVIEWViews.EMPLOYEEB
COMMENT='{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"teradata"}}'ASSELECT*FROMViews.EMPLOYEE
WHERE AREA ="AREAB";
/*<sc-view>RMSviews.EMPLOYEEB</sc-view>*/CREATEORREPLACEVIEW MyDatabase.RMSviews.EMPLOYEEB
ASSELECT*FROM MyDatabase.RMSviews.EMPLOYEE
WHERE AREA ="AREAB";/*<sc-view>Views.EMPLOYEEB</sc-view>*/CREATEORREPLACEVIEW MyDatabase.Views.EMPLOYEEB
ASSELECT*FROM MyDatabase.Views.EMPLOYEE
WHERE AREA ="AREAB";
/*<sc-view>RMSviews.EMPLOYEEB</sc-view>*/CREATEORREPLACEVIEW RMSviews.PUBLIC.EMPLOYEEB
ASSELECT*FROM RMSviews.PUBLIC.EMPLOYEE
WHERE AREA ="AREAB";/*<sc-view>Views.EMPLOYEEB</sc-view>*/CREATEORREPLACEVIEWViews.PUBLIC.EMPLOYEEB
ASSELECT*FROMViews.PUBLIC.EMPLOYEE
WHERE AREA ="AREAB";
CREATETABLE table1, no fallback,
no before journal,
no after journal (
c1 INTEGERNOTNULL,
f1 INTEGERNOTNULL,
p1 INTEGERNOTNULL,DATE,TIME,FOREIGNKEY(f1)REFERENCESWITHCHECKOPTION table2 (d1))UNIQUEPRIMARYINDEX(c1)PARTITIONBYCOLUMN(p1);
Teradata’s Volatile and Global Temporary tables are used for the temporary storage of data. Their difference lies in that the table definition (DDL) of Global Temporary tables is persisted in the Data Dictionary, while Volatile tables definition is not stored.
-- With dataCREATEORREPLACETABLE table1 CLONE table2
COMMENT='{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"teradata"}}';-- With no data--** SSC-FDM-0019 - SEMANTIC INFORMATION COULD NOT BE LOADED FOR table1. CHECK IF THE NAME IS INVALID OR DUPLICATED. **CREATEORREPLACETABLE table1 LIKE table2
COMMENT='{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"teradata"}}';
SnowConvert AI facilitates seamless SQL migrations to Snowflake by addressing challenges associated with reserved keywords. As per Snowflake’s reserved and limited keyword documentation, certain keywords cannot be used as column names, table names, or aliases without special handling. SnowConvert AI includes functionality to ensure SQL code compatibility in such cases.
Reserved ANSI Keywords as Column Names
For column names that match ANSI or Snowflakereserved keywords, SnowConvert AI automatically wraps the column name in double quotes (") to comply with Snowflake’s syntax rules. This adjustment ensures that queries with these column names compile correctly in Snowflake without requiring manual intervention.
Columns that match Snowflake-specific reserved keywords (for example, CONSTRAINT, CURRENT_DATE, CURRENT_TIME) may still cause compilation issues even when wrapped in quotes. SnowConvert AI detects these instances and generates a warning with code SSC-EWI-0045, prompting users to review and potentially rename these columns for compatibility.
Snowflake supports CHECK constraints with deterministic, scalar expressions. Teradata CHECK constraints pass through to Snowflake for supported expressions. Unsupported expressions (UDFs, non-deterministic functions) are flagged with SSC-EWI-0116.
Supported:
Basic CHECK constraints with scalar, deterministic expressions
In Teradata, the primary index constraint is declared outside of the create table statement, but in Snowflake it is required to be inside, as shown in the example “Simple Create Table”.
As shown in the example “Volatile and Global Temporary Table”, Snowflake does not support Teradata’s Global Temporary table option. It will be removed.
Teradata supports a FORMAT clause on column definitions to control how values are displayed or parsed. Snowflake does not support this clause. SnowConvert AI handles it differently depending on the column type and format pattern:
Column Type
Format Pattern
Issue
DDL Result
DML Result
Datetime (DATE, TIMESTAMP, TIME)
Snowflake standard (e.g., 'YYYY-MM-DD', 'HH:MI:SS', 'YYYY-MM-DDBHH:MI:SS')
The FORMAT value and column type are read from the CREATE TABLE statement and stored internally so that DML statements referencing those columns can be converted correctly. If the CREATE TABLE is not included in the conversion input, SnowConvert AI cannot determine the format, and no conversion functions will be added to DML statements. Always include the relevant DDL files in the conversion scope and verify that the converted code behaves correctly when FORMAT clauses are present.
Teradata’s WITH DEFAULT clause sets a system-default value to columns that are inserted with no values. This value is typically the equivalent of zero or empty.
CREATEORREPLACETABLE SAMPLE_TABLE
(
ID INT,-- Numeric Types
big_integer_col BIGINTDEFAULT0,
byteint_col BYTEINT DEFAULT0,
decimal_col DECIMAL(10,2)DEFAULT0,
double_precision_col DOUBLEPRECISIONDEFAULT0,
float_col FLOATDEFAULT0,
integer_col INTEGERDEFAULT0,
number_col NUMBER(38,18)DEFAULT0,
numeric_col NUMERIC(10,2)DEFAULT0,
real_col REALDEFAULT0,
smallint_col SMALLINTDEFAULT0,-- Character Types
char_col CHAR(50)DEFAULT'',
character_col CHARACTER(50)DEFAULT'',--clob_col CLOB,
char_varying_col CHARVARYING(100)DEFAULT'',--long_varchar_col LONG VARCHAR WITH DEFAULT,--long_varchar_graphic_col LONG VARCHAR CHARACTER SET GRAPHIC WITH DEFAULT,
varchar_col VARCHAR(255)DEFAULT'',--varchar_graphic_col VARCHAR(255) CHARACTER SET GRAPHIC WITH DEFAULT,-- Date and Time Types
date_col DATEDEFAULTCURRENT_DATE,
time_col TIMEDEFAULTCURRENT_TIME,
time_precision_col TIME(6)DEFAULTCURRENT_TIME(6),
timestamp_col TIMESTAMP-- !!!RESOLVE EWI!!! /*** SSC-EWI-0013 - EXCEPTION THROWN WHILE CONVERTING ITEM: Mobilize.T12Data.Sql.Ast.TdWithDefaultAttribute. LINE: 31 OF FILE: /Users/hbadillabonilla/Documents/Workspace/migrations-snowconvert/Tools/DocVerifier/out/temp/CUebOYutwG1Dca8jb0Fo/8921d487/SOURCE/Teradata_01.sql ***/!!!-- WITH DEFAULT,
timestamp_precision_col TIMESTAMP(6)-- !!!RESOLVE EWI!!! /*** SSC-EWI-0013 - EXCEPTION THROWN WHILE CONVERTING ITEM: Mobilize.T12Data.Sql.Ast.TdWithDefaultAttribute. LINE: 32 OF FILE: /Users/hbadillabonilla/Documents/Workspace/migrations-snowconvert/Tools/DocVerifier/out/temp/CUebOYutwG1Dca8jb0Fo/8921d487/SOURCE/Teradata_01.sql ***/!!!-- WITH DEFAULT,
tz_timestamp_col TIMESTAMP_TZ-- WITH DEFAULT-- !!!RESOLVE EWI!!! /*** SSC-EWI-0021 - WITH DEFAULT FOR 'TIMESTAMP WITH TIME ZONE' NOT SUPPORTED IN SNOWFLAKE ***/!!!,
tz_timestamp_precision_col TIMESTAMP_TZ(6)-- WITH DEFAULT-- !!!RESOLVE EWI!!! /*** SSC-EWI-0021 - WITH DEFAULT FOR 'TIMESTAMP(6) WITH TIME ZONE' NOT SUPPORTED IN SNOWFLAKE ***/!!!,
interval_col VARCHAR(21)!!!RESOLVE EWI!!!/*** SSC-EWI-0036 - INTERVAL DAY(4) DATA TYPE CONVERTED TO VARCHAR ***/!!!DEFAULT'0DAY',
interval_day_to_hour_col VARCHAR(21)!!!RESOLVE EWI!!!/*** SSC-EWI-0036 - INTERVAL DAY(4) TO HOUR DATA TYPE CONVERTED TO VARCHAR ***/!!!DEFAULT'0DAY',
interval_hour_col VARCHAR(21)!!!RESOLVE EWI!!!/*** SSC-EWI-0036 - INTERVAL HOUR(2) DATA TYPE CONVERTED TO VARCHAR ***/!!!DEFAULT'0HOUR',
interval_minute_col VARCHAR(21)!!!RESOLVE EWI!!!/*** SSC-EWI-0036 - INTERVAL MINUTE(2) DATA TYPE CONVERTED TO VARCHAR ***/!!!DEFAULT'0MINUTE',
interval_month_col VARCHAR(21)!!!RESOLVE EWI!!!/*** SSC-EWI-0036 - INTERVAL MONTH DATA TYPE CONVERTED TO VARCHAR ***/!!!DEFAULT'0MONTH',
interval_second_col VARCHAR(21)!!!RESOLVE EWI!!!/*** SSC-EWI-0036 - INTERVAL SECOND(2) DATA TYPE CONVERTED TO VARCHAR ***/!!!DEFAULT'0SECOND',
interval_year_col VARCHAR(21)!!!RESOLVE EWI!!!/*** SSC-EWI-0036 - INTERVAL YEAR(4) DATA TYPE CONVERTED TO VARCHAR ***/!!!DEFAULT'0YEAR',-- Binary Types-- blob_col BLOB(1000),
byte_col BINARY-- WITH DEFAULT-- !!!RESOLVE EWI!!! /*** SSC-EWI-0021 - WITH DEFAULT FOR 'BYTE(1000)' NOT SUPPORTED IN SNOWFLAKE ***/!!!,
varbyte_col BINARY(1000)-- WITH DEFAULT-- !!!RESOLVE EWI!!! /*** SSC-EWI-0021 - WITH DEFAULT FOR 'VARBYTE(1000)' NOT SUPPORTED IN SNOWFLAKE ***/!!!)
As shown in the table in the description table, some types are not supported and no default value will be set when transforming the WITH DEFAULT clause.
The Teradata CREATE MACRO defines one or more statements that are commonly used or that perform a complex operation, thus avoiding writing the same sequence of statements multiple times. The macro is executed when it is called by the EXECUTE statement.
Since there is no macro object in Snowflake, the conversion tool transforms Teradata macros into Snowflake Scripting stored procedures. Besides, to replicate the functionality of the returned result set, in Snowflake Scripting, the query that is supposed to return a data set from a macro is assigned to a RESULTSET variable which will then be returned.
CREATEORREPLACEPROCEDURE DEPOSITID (ID FLOAT)RETURNSTABLE()LANGUAGESQLCOMMENT='{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"teradata"}}'EXECUTEASCALLERAS$$
BEGIN
LET res RESULTSET := (SELECT * FROM DEPOSIT WHERE ACCOUNTNO=:ID);
RETURN TABLE(res);
END;
$$;CALL DEPOSITID(2);
SnowConvert AI supports the scenario where a macro calls another macro and, by transitivity, a result set is returned by getting the results from Snowflake’s RESULT_SCAN(LAST_QUERY_ID()).
In Teradata, macros can return more than one result set from a single macro.
Snowflake Scripting procedures only allow one result set to be returned per procedure. To replicate Teradata behavior, when there are two or more result sets to return, they are stored in temporary tables. The Snowflake Scripting procedure will return an array containing the name of the temporary tables.
REPLACE MACRO DEPOSITID (ID INT)AS(SELECT*FROM DEPOSIT WHERE ACCOUNTNO=4;SELECT*FROM DEPOSIT WHERE ACCOUNTNO=:ID;EXECUTE DEPOSITID(:ID););EXECUTE DEPOSITID(2);
By default, Snowflake procedures support the execution of any kind of SQL statements, including data reading or modification statements, making the SQL data access clause non-relevant. This clause will be ignored when converting the procedure.
2. Top Level Objects in Assessment Report
Elements (Temporal tables or Views) inside Stored Procedures are being counted in the Assessment report as Top Level Objects. The SnowConvert AI team is now working on a fix for this scenario.