PREPARE
Translation specification to convert Teradata PREPARE statement to Snowflake Scripting. This section review the PREPARE pattern related to a cursor logic.
Description
Prepares the dynamic DECLARE CURSOR statement to allow the creation of different result sets. Allows dynamic parameter markers.
For more information, please review the following documentation.
Tedarata syntax:
PREPARE statement_name FROM { 'statement_string' | statement_string_variable } ;
Where:
statement_name is the same identifier as
statement_name
in a DECLARE CURSOR statement.statement_string is the SQL text that is to be executed dynamically.
statement_string_variable is the name of an SQL local variable, or an SQL parameter or string variable, that contains the SQL text string to be executed dynamically.
Important information
For this transformation, the cursors are renamed since they cannot be dynamically updated.
Sample Source Patterns
Data setting for examples
For this example, please use the following complementary queries in the case that you want to run each case.
CREATE TABLE MyTemporaryTable(
Col1 INTEGER
);
INSERT INTO MyTemporaryTable(col1) VALUES (1);
SELECT * FROM databaseTest.MyTemporaryTable;
CREATE TABLE MyStatusTable (
Col1 VARCHAR(2)
);
SELECT * FROM MyStatusTable;
CREATE TABLE MyTemporaryTable (
Col1 INTEGER
)
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},"attributes":{"component":"teradata"}}'
;
INSERT INTO MyTemporaryTable (col1) VALUES (1);
SELECT * FROM MyTemporaryTable;
CREATE TABLE MyStatusTable (
Col1 VARCHAR(2)
)
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},"attributes":{"component":"teradata"}}'
;
SELECT * FROM MyStatusTable;
Simple scenario
This example reviews the functionality for the cases where a single cursor is being used one single time.
Teradata
REPLACE PROCEDURE simple_scenario()
BEGIN
--Variables for the example's procedure_results
DECLARE SQL_string_sel VARCHAR(200) DEFAULT 'SELECT * FROM MyTemporaryTable';
DECLARE procedure_result INTEGER DEFAULT 0;
-- Actual Cursor usage
DECLARE C1 CURSOR FOR S1;
PREPARE S1 FROM SQL_string_sel;
OPEN C1;
FETCH C1 INTO procedure_result;
INSERT INTO databaseTest.MyStatusTable(Col1) VALUES (procedure_result);
CLOSE C1;
END;
CALL databaseTest.simple_scenario();
SELECT * FROM MyStatusTable;
1
Snowflake Scripting
Usages for cursors must be renamed and declared again.
CREATE OR REPLACE PROCEDURE simple_scenario ()
RETURNS VARCHAR
LANGUAGE SQL
COMMENT = '{ ""origin"": ""sf_sc"", ""name"": ""snowconvert"", ""version"": { ""major"": 0, ""minor"": 0, ""patch"": ""0"" }, ""attributes"": { ""component"": ""none"", ""convertedOn"": ""01/01/0001"" }}'
EXECUTE AS CALLER
AS
$$
DECLARE
--Variables for the example's procedure_results
SQL_string_sel VARCHAR(200) DEFAULT 'SELECT
* FROM
MyTemporaryTable';
procedure_result INTEGER DEFAULT 0;
S1 RESULTSET;
prepareQuery_aux_sql VARCHAR;
BEGIN
-- Actual Cursor usage
prepareQuery_aux_sql := SQL_string_sel;
S1 := (
EXECUTE IMMEDIATE prepareQuery_aux_sql
);
LET CURSOR_S1_INSTANCE_V0 CURSOR
FOR
S1;
OPEN CURSOR_S1_INSTANCE_V0;
FETCH
CURSOR_S1_INSTANCE_V0
INTO
procedure_result;
INSERT INTO databaseTest.MyStatusTable (Col1)
VALUES (procedure_result);
CLOSE CURSOR_S1_INSTANCE_V0;
END;
$$;
CALL databaseTest.simple_scenario();
SELECT * FROM MyStatusTable;
1
Simple scenario with RETURN ONLY
Teradata
REPLACE PROCEDURE simple_scenario()
DYNAMIC RESULT SETS 1
BEGIN
DECLARE SQL_string_sel VARCHAR(200) DEFAULT 'SELECT * FROM MyTemporaryTable';
DECLARE procedure_result VARCHAR(100);
DECLARE C1 CURSOR WITH RETURN ONLY FOR S1;
SET procedure_result = '';
PREPARE S1 FROM SQL_string_sel;
OPEN C1;
END;
CALL databaseTest.simple_scenario();
SELECT * FROM MyStatusTable;
1
Snowflake Scripting
Usages for cursors must be renamed and declared again.
CREATE OR REPLACE PROCEDURE simple_scenario ()
RETURNS TABLE (
)
LANGUAGE SQL
COMMENT = '{ ""origin"": ""sf_sc"", ""name"": ""snowconvert"", ""version"": { ""major"": 0, ""minor"": 0, ""patch"": ""0"" }, ""attributes"": { ""component"": ""none"", ""convertedOn"": ""01/01/0001"" }}'
EXECUTE AS CALLER
AS
$$
DECLARE
SQL_string_sel VARCHAR(200) DEFAULT 'SELECT
* FROM
MyTemporaryTable';
procedure_result VARCHAR(100);
S1 RESULTSET;
prepareQuery_aux_sql VARCHAR;
BEGIN
procedure_result := '';
prepareQuery_aux_sql := SQL_string_sel;
S1 := (
EXECUTE IMMEDIATE prepareQuery_aux_sql
);
LET CURSOR_S1_INSTANCE_V0 CURSOR
FOR
S1;
OPEN CURSOR_S1_INSTANCE_V0;
RETURN TABLE(resultset_from_cursor(CURSOR_S1_INSTANCE_V0));
END;
$$;
CALL databaseTest.simple_scenario();
SELECT * FROM MyStatusTable;
1
Reused cursor case
Teradata
CREATE PROCEDURE fetch_simple_reused_cursor(OUT procedure_result INTEGER)
BEGIN
DECLARE SQL_string_sel VARCHAR(200) DEFAULT 'SELECT col1 FROM MyTemporaryTable WHERE col1 = 1';
DECLARE C1 CURSOR FOR S1;
PREPARE S1 FROM SQL_string_sel;
OPEN C1;
FETCH C1 INTO procedure_result;
CLOSE C1;
PREPARE S1 FROM SQL_string_sel;
OPEN C1;
FETCH C1 INTO procedure_result;
CLOSE C1;
END;
No returning information.
Snowflake Scripting
Usages for cursors must be renamed and declared again.
CREATE OR REPLACE PROCEDURE fetch_simple_reused_cursor (
-- OUT
PROCEDURE_RESULT INTEGER)
RETURNS VARIANT
LANGUAGE SQL
COMMENT = '{ "origin": "sf_sc", "name": "snowconvert", "version": { "major": 0, "minor": 0, "patch": "0" }, "attributes": { "component": "teradata", "convertedOn": "07/24/2024" }}'
EXECUTE AS CALLER
AS
$$
DECLARE
SQL_string_sel VARCHAR(200) DEFAULT 'SELECT
col1 FROM
MyTemporaryTable
WHERE col1 = 1';
S1 RESULTSET;
prepareQuery_aux_sql VARCHAR;
BEGIN
prepareQuery_aux_sql := SQL_string_sel;
S1 := (
EXECUTE IMMEDIATE prepareQuery_aux_sql
);
LET CURSOR_S1_INSTANCE_V0 CURSOR
FOR
S1;
OPEN CURSOR_S1_INSTANCE_V0;
FETCH
CURSOR_S1_INSTANCE_V0
INTO procedure_result;
CLOSE CURSOR_S1_INSTANCE_V0;
prepareQuery_aux_sql := SQL_string_sel;
S1 := (
EXECUTE IMMEDIATE prepareQuery_aux_sql
);
LET CURSOR_S1_INSTANCE_V1 CURSOR
FOR
S1;
OPEN CURSOR_S1_INSTANCE_V1;
FETCH
CURSOR_S1_INSTANCE_V1
INTO procedure_result;
CLOSE CURSOR_S1_INSTANCE_V1;
RETURN procedure_result;
END;
$$;
No returning information.
Modified query before usage
Teradata
REPLACE PROCEDURE fetch_modified_query_cursor()
BEGIN
--Variables for the example's procedure_results
DECLARE SQL_string_sel VARCHAR(200) DEFAULT 'SELECT col1 FROM MyTemporaryTable WHERE col1 = 1';
DECLARE procedure_result INTEGER DEFAULT 0;
-- Actual Cursor usages
DECLARE C1 CURSOR FOR S1;
PREPARE S1 FROM SQL_string_sel;
-- This modification does not take effect since S1 is already staged for the Cursor
SET SQL_string_sel = 'SELECT col1 FROM MyTemporaryTable WHERE col1 = 0';
OPEN C1;
FETCH C1 INTO procedure_result;
INSERT INTO databaseTest.MyStatusTable(Col1) VALUES (procedure_result);
CLOSE C1;
END;
CALL databaseTest.simple_scenario();
SELECT * FROM MyStatusTable;
1
Snowflake Scripting
Usages for cursors must be renamed and declared again.
CREATE OR REPLACE PROCEDURE fetch_modified_query_cursor ()
RETURNS VARCHAR
LANGUAGE SQL
COMMENT = '{ ""origin"": ""sf_sc"", ""name"": ""snowconvert"", ""version"": { ""major"": 0, ""minor"": 0, ""patch"": ""0"" }, ""attributes"": { ""component"": ""none"", ""convertedOn"": ""01/01/0001"" }}'
EXECUTE AS CALLER
AS
$$
DECLARE
--Variables for the example's procedure_results
SQL_string_sel VARCHAR(200) DEFAULT 'SELECT
col1 FROM
MyTemporaryTable
WHERE col1 = 1';
procedure_result INTEGER DEFAULT 0;
S1 RESULTSET;
prepareQuery_aux_sql VARCHAR;
BEGIN
-- Actual Cursor usages
prepareQuery_aux_sql := SQL_string_sel;
S1 := (
EXECUTE IMMEDIATE prepareQuery_aux_sql
);
LET CURSOR_S1_INSTANCE_V0 CURSOR
FOR
S1;
-- This modification does not take effect since S1 is already staged for the Cursor
SQL_string_sel := 'SELECT
col1 FROM
MyTemporaryTable
WHERE col1 = 0';
OPEN CURSOR_S1_INSTANCE_V0;
FETCH
CURSOR_S1_INSTANCE_V0
INTO
procedure_result;
INSERT INTO databaseTest.MyStatusTable (Col1)
VALUES (procedure_result);
CLOSE CURSOR_S1_INSTANCE_V0;
END;
$$;
CALL databaseTest.simple_scenario();
SELECT * FROM MyStatusTable;
1
Simple cursor combined with no PREPARE pattern
Teradata
REPLACE PROCEDURE fetch_cursor_ignored_query_cursor()
BEGIN
--Variables for the example's procedure_results
DECLARE SQL_string_sel VARCHAR(200) DEFAULT 'SELECT * FROM MyTemporaryTable WHERE col1 = 1';
DECLARE intermediate_result INTEGER;
DECLARE procedure_result INTEGER DEFAULT 0;
DECLARE C2 CURSOR FOR SELECT col1 FROM MyTemporaryTable WHERE col1 = 1;
-- Actual Cursor usage
DECLARE C1 CURSOR FOR S1;
PREPARE S1 FROM SQL_string_sel;
OPEN C1;
FETCH C1 INTO intermediate_result;
CLOSE C1;
SET procedure_result = intermediate_result;
INSERT INTO databaseTest.MyStatusTable(Col1) VALUES (procedure_result);
OPEN C2;
FETCH C2 INTO intermediate_result;
CLOSE C2;
SET procedure_result = procedure_result + intermediate_result;
END;
CALL databaseTest.simple_scenario();
SELECT * FROM MyStatusTable;
1
Snowflake Scripting
Usages for cursors must be renamed and declared again.
CREATE OR REPLACE PROCEDURE fetch_cursor_ignored_query_cursor ()
RETURNS VARCHAR
LANGUAGE SQL
COMMENT = '{ ""origin"": ""sf_sc"", ""name"": ""snowconvert"", ""version"": { ""major"": 0, ""minor"": 0, ""patch"": ""0"" }, ""attributes"": { ""component"": ""none"", ""convertedOn"": ""01/01/0001"" }}'
EXECUTE AS CALLER
AS
$$
DECLARE
--Variables for the example's procedure_results
SQL_string_sel VARCHAR(200) DEFAULT 'SELECT
* FROM
MyTemporaryTable
WHERE col1 = 1';
intermediate_result INTEGER;
procedure_result INTEGER DEFAULT 0;
S1 RESULTSET;
prepareQuery_aux_sql VARCHAR;
BEGIN
-- Actual Cursor usage
LET C2 CURSOR
FOR
SELECT
col1
FROM
MyTemporaryTable
WHERE
col1 = 1;
prepareQuery_aux_sql := SQL_string_sel;
S1 := (
EXECUTE IMMEDIATE prepareQuery_aux_sql
);
LET CURSOR_S1_INSTANCE_V0 CURSOR
FOR
S1;
OPEN CURSOR_S1_INSTANCE_V0;
FETCH
CURSOR_S1_INSTANCE_V0
INTO
intermediate_result;
CLOSE CURSOR_S1_INSTANCE_V0;
procedure_result := intermediate_result;
INSERT INTO databaseTest.MyStatusTable (Col1)
VALUES (procedure_result);
OPEN C2;
FETCH
C2
INTO
intermediate_result;
CLOSE C2;
procedure_result := procedure_result + intermediate_result;
END;
$$;
CALL databaseTest.simple_scenario();
SELECT * FROM MyStatusTable;
1
Prepare combined with nested cursors
Teradata
REPLACE PROCEDURE fetch_nested_cursor()
BEGIN
--Variables for the example's procedure_results
DECLARE SQL_string_sel VARCHAR(200) DEFAULT 'SELECT col1 FROM MyTemporaryTable WHERE col1 = 1';
DECLARE intermediate_result INTEGER;
DECLARE C2 CURSOR FOR SELECT col1 FROM MyTemporaryTable WHERE col1 = 1;
-- Actual Cursor usage
DECLARE C1 CURSOR FOR S1;
PREPARE S1 FROM SQL_string_sel;
OPEN C1;
OPEN C2;
FETCH C2 INTO intermediate_result;
CLOSE C2;
FETCH C1 INTO intermediate_result;
CLOSE C1;
END;
No returning information.
Snowflake Scripting
Usages for cursors must be renamed and declared again.
CREATE OR REPLACE PROCEDURE fetch_nested_cursor ()
RETURNS VARCHAR
LANGUAGE SQL
COMMENT = '{ ""origin"": ""sf_sc"", ""name"": ""snowconvert"", ""version"": { ""major"": 0, ""minor"": 0, ""patch"": ""0"" }, ""attributes"": { ""component"": ""none"", ""convertedOn"": ""01/01/0001"" }}'
EXECUTE AS CALLER
AS
$$
DECLARE
--Variables for the example's procedure_results
SQL_string_sel VARCHAR(200) DEFAULT 'SELECT
col1 FROM
MyTemporaryTable
WHERE col1 = 1';
intermediate_result INTEGER;
S1 RESULTSET;
prepareQuery_aux_sql VARCHAR;
BEGIN
-- Actual Cursor usage
LET C2 CURSOR
FOR
SELECT
col1
FROM
MyTemporaryTable
WHERE
col1 = 1;
prepareQuery_aux_sql := SQL_string_sel;
S1 := (
EXECUTE IMMEDIATE prepareQuery_aux_sql
);
LET CURSOR_S1_INSTANCE_V0 CURSOR
FOR
S1;
OPEN CURSOR_S1_INSTANCE_V0;
OPEN C2;
FETCH
C2
INTO
intermediate_result;
CLOSE C2;
FETCH
CURSOR_S1_INSTANCE_V0
INTO
intermediate_result;
CLOSE CURSOR_S1_INSTANCE_V0;
END;
$$;
No returning information.
Variable markers without variable reordering
This case is not supported yet.
Teradata
CREATE PROCEDURE PREPARE_ST_TEST()
BEGIN
DECLARE ctry_list VARCHAR(100);
DECLARE SQL_string_sel VARCHAR(255);
DECLARE col_value NUMBER;
DECLARE C1 CURSOR FOR S1;
SET ctry_list = '';
SET col_value = 1;
SET SQL_string_sel = 'SELECT * FROM databaseTest.MyTemporaryTable where Col1 = ?';
PREPARE S1 FROM SQL_string_sel;
OPEN C1 USING col_value;
FETCH C1 INTO ctry_list;
IF (ctry_list <> '') THEN
INSERT INTO databaseTest.MyStatusTable(col1) VALUES ('ok');
END IF;
CLOSE C1;
END;
CALL PREPARE_ST_TEST();
SELECT * FROM MyStatusTable;
ok
Snowflake Scripting
Usages for cursors must be renamed and declared again.
CREATE OR REPLACE PROCEDURE PREPARE_ST_TEST_MARKERS ()
RETURNS VARCHAR
LANGUAGE SQL
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},"attributes":{"component":"teradata"}}'
EXECUTE AS CALLER
AS
$$
DECLARE
p1 RESULTSET;
p1_sql VARCHAR DEFAULT '';
BEGIN
LET ctry_list VARCHAR(100);
LET SQL_string_sel VARCHAR(255);
LET col_value NUMBER(38, 18);
LET S1 RESULTSET;
ctry_list := '';
col_value := 1;
SQL_string_sel := 'SELECT * FROM MyTemporaryTable WHERE Col1 = ?';
p1_sql := SQL_string_sel;
S1 := (
EXECUTE IMMEDIATE p1_sql USING (col_value)
);
LET C1 CURSOR FOR S1;
OPEN C1;
FETCH C1 INTO ctry_list;
IF (RTRIM(ctry_list) <> '') THEN
INSERT INTO MyStatusTable (col1)
VALUES ('ok');
END IF;
CLOSE C1;
END;
$$;
ok
Variable markers with variable reordering
This case is not supported yet.
When there are variables setting the value into different ones between the PREPARE
statement and OPEN
cursor in Teradata, It is necessary to move this variable before the EXECUTE IMMEDIATE
in Snowflake. So, the dynamic variable information is updated at the moment of running the dynamic query.
Teradata
CREATE PROCEDURE PREPARE_ST_TEST()
BEGIN
DECLARE ctry_list VARCHAR(100);
DECLARE SQL_string_sel VARCHAR(255);
DECLARE col_name NUMBER;
DECLARE C1 CURSOR FOR S1;
SET ctry_list = '';
SET col_name = 1;
SET SQL_string_sel = 'SELECT * FROM databaseTest.MyTemporaryTable where Col1 = ?';
PREPARE S1 FROM SQL_string_sel;
SET col_name = 2; // change value before open cursor
OPEN C1 USING col_name;
FETCH C1 INTO ctry_list;
IF (ctry_list <> '') THEN
INSERT INTO databaseTest.MyStatusTable(col1) VALUES ('ok');
END IF;
CLOSE C1;
END;
CALL PREPARE_ST_TEST();
SELECT * FROM MyStatusTable;
"MyStatusTable" should be empty.
Snowflake Scripting
Usages for cursors must be renamed and declared again.
CREATE OR REPLACE PROCEDURE PREPARE_ST_TEST_MARKERS ()
RETURNS VARCHAR
LANGUAGE SQL
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},"attributes":{"component":"teradata"}}'
EXECUTE AS CALLER
AS
$$
DECLARE
p1 RESULTSET;
p1_sql VARCHAR DEFAULT '';
BEGIN
LET ctry_list VARCHAR(100);
LET SQL_string_sel VARCHAR(255);
LET col_value NUMBER(38, 18);
LET S1 RESULTSET;
ctry_list := '';
col_value := 1;
SQL_string_sel := 'SELECT * FROM MyTemporaryTable WHERE Col1 = ?';
p1_sql := SQL_string_sel;
col_value:= 2; // Move variable setting before the EXECUTE IMMEDIATE
S1 := (
EXECUTE IMMEDIATE p1_sql USING (col_value)
);
LET C1 CURSOR FOR S1;
OPEN C1;
FETCH C1 INTO ctry_list;
IF (RTRIM(ctry_list) <> '') THEN
INSERT INTO MyStatusTable (col1)
VALUES ('ok');
END IF;
CLOSE C1;
END;
$$;
CALL PREPARE_ST_TEST();
SELECT * FROM MyStatusTable;
"MyStatusTable" should be empty.
Anonymous blocks - Declaration outside the block
This case is not supported yet.
Teradata
REPLACE PROCEDURE anonymous_blocks_case(OUT procedure_result INTEGER)
BEGIN
--Variables for the example's procedure_results
DECLARE SQL_string_sel VARCHAR(200) DEFAULT 'SELECT col1 FROM MyTemporaryTable WHERE col1 = 1';
-- Actual Cursor usage
DECLARE C1 CURSOR FOR S1;
DECLARE C2 CURSOR FOR S2;
PREPARE S1 FROM SQL_string_sel;
OPEN C1;
FETCH C1 INTO procedure_result;
CLOSE C1;
BEGIN
PREPARE S2 FROM SQL_string_sel;
OPEN C2;
FETCH C2 INTO procedure_result;
CLOSE C2;
END;
OPEN C1;
CLOSE C1;
END;
No returning information.
CREATE OR REPLACE PROCEDURE anonymous_blocks_case (
-- OUT
PROCEDURE_RESULT INTEGER)
RETURNS VARIANT
LANGUAGE SQL
COMMENT = '{ "origin": "sf_sc", "name": "snowconvert", "version": { "major": 0, "minor": 0, "patch": "0" }, "attributes": { "component": "none", "convertedOn": "01/01/0001" }}'
EXECUTE AS CALLER
AS
$$
DECLARE
--Variables for the example's procedure_results
SQL_string_sel VARCHAR(200) DEFAULT 'SELECT
col1 FROM
MyTemporaryTable
WHERE col1 = 1';
S1 RESULTSET;
prepareQuery_aux_sql VARCHAR;
S2 RESULTSET;
BEGIN
-- Actual Cursor usage
prepareQuery_aux_sql := SQL_string_sel
S1 := (
EXECUTE IMMEDIATE prepareQuery_aux_sql
);
LET CURSOR_S1_INSTANCE_V0 CURSOR
FOR
S1;
OPEN CURSOR_S1_INSTANCE_V0;
FETCH
CURSOR_S1_INSTANCE_V0
INTO
procedure_result;
CLOSE CURSOR_S1_INSTANCE_V0;
BEGIN
prepareQuery_aux_sql := SQL_string_sel
S2 := (
EXECUTE IMMEDIATE prepareQuery_aux_sql
);
LET CURSOR_S2_INSTANCE_V# CURSOR
FOR
S1;
OPEN CURSOR_S2_INSTANCE_V#;
FETCH
CURSOR_S2_INSTANCE_V#
INTO
procedure_result;
CLOSE CURSOR_S2_INSTANCE_V#;
END;
OPEN CURSOR_S1_INSTANCE_V0; -- NAME REMAINS AS NEEDED IN LOGIC
CLOSE CURSOR_S1_INSTANCE_V0;
RETURN null;
END;
$$;
No returning information.
Known Issues
Review carefully nested cursors and conditionals, if that is the case.
Related EWIs
No related EWIs.
Last updated