SnowConvert:PL/SQL para Snowflake Scripting¶
ASSIGNMENT STATEMENT¶
Descrição¶
A instrução de atribuição define o valor de um item de dados como um valor válido.\ (Instrução ASSIGNMENT da referência de linguagem Oracle PL/SQL)
Nota
Algumas partes do código de saída foram omitidas por motivos de clareza.
assignment_statement_target := expression ;
assignment_statement_target =
{ collection_variable [ ( index ) ]
| cursor_variable
| :host_cursor_variable
| object[.attribute]
| out_parameter
| placeholder
| record_variable[.field]
| scalar_variable
}
LET <variable_name> <type> { DEFAULT | := } <expression> ;
LET <variable_name> { DEFAULT | := } <expression> ;
Nota
LET
não é necessária para instruções de atribuição quando a variável tiver sido declarada anteriormente. Consulte a documentação do Snowflake Assignment para obter mais informações.
Amostra de padrões da origem¶
1. Scalar Variables¶
Oracle¶
CREATE TABLE TASSIGN (
COL1 NUMBER,
COL2 NUMBER,
COL3 VARCHAR(20),
COL4 VARCHAR(20)
);
CREATE OR REPLACE PROCEDURE PSCALAR
AS
var1 NUMBER := 40;
var2 NUMBER := 22.50;
var3 VARCHAR(20);
var4 BOOLEAN;
var5 NUMBER;
BEGIN
var1 := 1;
var2 := 2.1;
var2 := var2 + var2;
var3 := 'Hello World';
var4 := true;
var4 := var1 > 500;
IF var4 THEN
var5 := 0;
ELSE
var5 := 1;
END IF;
INSERT INTO TASSIGN VALUES(var1, var2, var3, var5);
END;
CALL PSCALAR();
SELECT * FROM TASSIGN;
COL1|COL2|COL3 |COL4|
----+----+-----------+----+
1| 4.2|Hello World| 1|
Script Snowflake¶
CREATE OR REPLACE TABLE TASSIGN (
COL1 NUMBER(38, 18) /*** SSC-FDM-0006 - NUMBER TYPE COLUMN MAY NOT BEHAVE SIMILARLY IN SNOWFLAKE. ***/,
COL2 NUMBER(38, 18) /*** SSC-FDM-0006 - NUMBER TYPE COLUMN MAY NOT BEHAVE SIMILARLY IN SNOWFLAKE. ***/,
COL3 VARCHAR(20),
COL4 VARCHAR(20)
)
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"oracle"}}'
;
CREATE OR REPLACE PROCEDURE PSCALAR ()
RETURNS VARCHAR
LANGUAGE SQL
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"oracle"}}'
EXECUTE AS CALLER
AS
$$
DECLARE
var1 NUMBER(38, 18) := 40;
var2 NUMBER(38, 18) := 22.50;
var3 VARCHAR(20);
var4 BOOLEAN;
var5 NUMBER(38, 18);
BEGIN
var1 := 1;
var2 := 2.1;
var2 := :var2 + :var2;
var3 := 'Hello World';
var4 := true;
var4 := :var1 > 500;
IF (:var4) THEN
var5 := 0;
ELSE
var5 := 1;
END IF;
INSERT INTO TASSIGN
VALUES(:var1, :var2, :var3, :var5);
END;
$$;
CALL PSCALAR();
SELECT * FROM
TASSIGN;
COL1 |COL2 |COL3 |COL4|
--------------------+--------------------+-----------+----+
1.000000000000000000|4.000000000000000000|Hello World|1 |
Aviso
A transformação de alguns tipos de dados precisa ser atualizada, o que pode causar resultados diferentes. Por exemplo, NUMBER para NUMBER arredonda o valor e o ponto decimal é perdido. Já existe um item de trabalho para essa questão.
2. Out Parameter Assignment¶
Para obter mais informações sobre como os parâmetros de saída estão sendo convertidos, consulte o seguinte artigo Parâmetros de saída.
3. Not Supported Assignments¶
Oracle¶
CREATE OR REPLACE PROCEDURE pinvalid(out_parameter IN OUT NUMBER)
AS
record_variable employees%ROWTYPE;
TYPE cursor_type IS REF CURSOR;
cursor1 cursor_type;
cursor2 SYS_REFCURSOR;
TYPE collection_type IS TABLE OF NUMBER INDEX BY VARCHAR(64);
collection_variable collection_type;
BEGIN
--Record Example
record_variable.last_name := 'Ortiz';
--Cursor Example
cursor1 := cursor2;
--Collection
collection_variable('Test') := 5;
--Out Parameter
out_parameter := 123;
END;
Script Snowflake¶
--** SSC-FDM-0007 - MISSING DEPENDENT OBJECT "employees" **
CREATE OR REPLACE PROCEDURE pinvalid (out_parameter NUMBER(38, 18))
RETURNS VARIANT
LANGUAGE SQL
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},"attributes":{"component":"oracle"}}'
EXECUTE AS CALLER
AS
$$
DECLARE
record_variable OBJECT !!!RESOLVE EWI!!! /*** SSC-EWI-0036 - ROWTYPE DATA TYPE CONVERTED TO OBJECT ***/!!! := OBJECT_CONSTRUCT();
-- !!!RESOLVE EWI!!! /*** SSC-EWI-0058 - FUNCTIONALITY FOR 'PL REF CURSOR TYPE DEFINITION' IS NOT CURRENTLY SUPPORTED BY SNOWFLAKE SCRIPTING ***/!!!
-- TYPE cursor_type IS REF CURSOR;
cursor1_res RESULTSET;
cursor2_res RESULTSET;
-- !!!RESOLVE EWI!!! /*** SSC-EWI-0058 - FUNCTIONALITY FOR 'PL COLLECTION TYPE DEFINITION' IS NOT CURRENTLY SUPPORTED BY SNOWFLAKE SCRIPTING ***/!!!
-- TYPE collection_type IS TABLE OF NUMBER INDEX BY VARCHAR(64);
collection_variable VARIANT !!!RESOLVE EWI!!! /*** SSC-EWI-0062 - CUSTOM TYPE 'collection_type' USAGE CHANGED TO VARIANT ***/!!!;
BEGIN
--Record Example
record_variable := OBJECT_INSERT(record_variable, 'LAST_NAME', 'Ortiz', true);
--Cursor Example
!!!RESOLVE EWI!!! /*** SSC-EWI-OR0108 - THE FOLLOWING ASSIGNMENT STATEMENT IS NOT SUPPORTED BY SNOWFLAKE SCRIPTING ***/!!!
cursor1 := :cursor2;
--Collection
!!!RESOLVE EWI!!! /*** SSC-EWI-OR0108 - THE FOLLOWING ASSIGNMENT STATEMENT IS NOT SUPPORTED BY SNOWFLAKE SCRIPTING ***/!!!
collection_variable('Test') := 5;
--Out Parameter
out_parameter := 123;
RETURN out_parameter;
END;
$$;
Problemas conhecidos¶
1. Several Unsupported Assignment Statements¶
Atualmente, a transformação de variáveis de cursor, coleção, registro e tipo definido pelo usuário não é suportada pelo Snow Scripting. Portanto, as instruções de atribuição que usam essas variáveis são comentadas e marcadas como não suportadas. Alterar essas variáveis para tipos de dados semiestruturados do Snowflake pode ajudar como solução alternativa em alguns cenários.
CALL¶
Descrição¶
Há dois tipos de instruções de chamada no Oracle:
1-Instrução CALL:¶
Use a instrução CALL
para executar uma rotina (um procedimento ou função autônoma, ou um procedimento ou função definido em um tipo ou pacote) em SQL. (CALL da referência de linguagem Oracle SQL)
Especificação de 2 chamadas:¶
Uma especificação de chamada declara um método Java ou um subprograma de linguagem C para que possa ser chamado a partir de PL/SQL. (Especificação de chamada da referência de linguagem Oracle SQL)
A especificação CALL Snowflake Scripting, pois faz parte das bibliotecas de desenvolvimento para C e JAVA, não é uma instrução SQL, portanto, essa instrução não é transformada.
Problemas conhecidos¶
Não foram encontrados problemas.
EWIs relacionados¶
Sem EWIs relacionados.
CASE¶
Descrição¶
A instrução CASE
seleciona uma sequência de condições e executa a instrução correspondente. Para obter mais informações sobre Oracle CASE, veja aqui.
Nota
Algumas partes do código de saída foram omitidas por motivos de clareza.
Caso simples¶
[ <<label>> ] CASE case_operand
WHEN boolean_expression THEN statement ;
[ WHEN boolean_expression THEN statement ; ]...
[ ELSE statement [ statement ]... ;
END CASE [ label ] ;
CASE ( <expression_to_match> )
WHEN <expression> THEN
<statement>;
[ <statement>; ... ]
[ WHEN ... ]
[ ELSE
<statement>;
[ <statement>; ... ]
]
END [ CASE ] ;
Caso pesquisado¶
[ <<label>> ] CASE
WHEN boolean_expression THEN statement ;
[ WHEN boolean_expression THEN statement ; ]...
[ ELSE statement [ statement ]... ;
END CASE [ label ];
CASE
WHEN <boolean_expression> THEN
<statement>;
[ <statement>; ... ]
[ WHEN ... ]
[ ELSE
<statement>;
[ <statement>; ... ]
]
END [ CASE ] ;
Amostra de padrões da origem¶
Exemplo de tabela auxiliar¶
CREATE TABLE case_table(col varchar(30));
CREATE OR REPLACE TABLE case_table (col varchar(30))
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"oracle"}}'
;
Caso simples¶
Oracle¶
CREATE OR REPLACE PROCEDURE caseExample1 ( grade NUMBER )
IS
RESULT VARCHAR(20);
BEGIN
<<CASE1>>
CASE grade
WHEN 10 THEN RESULT:='Excellent';
WHEN 9 THEN RESULT:='Very Good';
WHEN 8 THEN RESULT:='Good';
WHEN 7 THEN RESULT:='Fair';
WHEN 6 THEN RESULT:='Poor';
ELSE RESULT:='No such grade';
END CASE CASE1;
INSERT INTO CASE_TABLE(COL) VALUES (RESULT);
END;
CALL caseExample1(6);
CALL caseExample1(4);
CALL caseExample1(10);
SELECT * FROM CASE_TABLE;
|COL |
|-------------|
|Poor |
|No such grade|
|Excellent |
Script Snowflake¶
CREATE OR REPLACE PROCEDURE caseExample1 (grade NUMBER(38, 18))
RETURNS VARCHAR
LANGUAGE SQL
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"oracle"}}'
EXECUTE AS CALLER
AS
$$
DECLARE
RESULT VARCHAR(20);
BEGIN
!!!RESOLVE EWI!!! /*** SSC-EWI-0094 - LABEL DECLARATION FOR A STATEMENT IS NOT SUPPORTED BY SNOWFLAKE SCRIPTING <<CASE1>> ***/!!!
CASE :grade
WHEN 10 THEN
RESULT := 'Excellent';
WHEN 9 THEN
RESULT := 'Very Good';
WHEN 8 THEN
RESULT := 'Good';
WHEN 7 THEN
RESULT := 'Fair';
WHEN 6 THEN
RESULT := 'Poor';
ELSE
RESULT := 'No such grade';
END CASE;
INSERT INTO CASE_TABLE(COL) VALUES (:RESULT);
END;
$$;
CALL caseExample1(6);
CALL caseExample1(4);
CALL caseExample1(10);
--** SSC-FDM-0007 - MISSING DEPENDENT OBJECT "CASE_TABLE" **
SELECT * FROM
CASE_TABLE;
|COL |
|-------------|
|Poor |
|No such grade|
|Excellent |
Caso pesquisado¶
Oracle¶
CREATE OR REPLACE PROCEDURE caseExample2 ( grade NUMBER )
IS
RESULT VARCHAR(20);
BEGIN
<<CASE1>>
CASE
WHEN grade = 10 THEN RESULT:='Excellent';
WHEN grade = 9 THEN RESULT:='Very Good';
WHEN grade = 8 THEN RESULT:='Good';
WHEN grade = 7 THEN RESULT:='Fair';
WHEN grade = 6 THEN RESULT:='Poor';
ELSE RESULT:='No such grade';
END CASE CASE1;
INSERT INTO CASE_TABLE(COL) VALUES (RESULT);
END;
CALL caseExample2(6);
CALL caseExample2(4);
CALL caseExample2(10);
SELECT * FROM CASE_TABLE;
|COL |
|-------------|
|Poor |
|No such grade|
|Excellent |
Script Snowflake¶
CREATE OR REPLACE PROCEDURE caseExample2 (grade NUMBER(38, 18))
RETURNS VARCHAR
LANGUAGE SQL
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"oracle"}}'
EXECUTE AS CALLER
AS
$$
DECLARE
RESULT VARCHAR(20);
BEGIN
!!!RESOLVE EWI!!! /*** SSC-EWI-0094 - LABEL DECLARATION FOR A STATEMENT IS NOT SUPPORTED BY SNOWFLAKE SCRIPTING <<CASE1>> ***/!!!
CASE
WHEN :grade = 10 THEN
RESULT := 'Excellent';
WHEN :grade = 9 THEN
RESULT := 'Very Good';
WHEN :grade = 8 THEN
RESULT := 'Good';
WHEN :grade = 7 THEN
RESULT := 'Fair';
WHEN :grade = 6 THEN
RESULT := 'Poor';
ELSE
RESULT := 'No such grade';
END CASE;
INSERT INTO CASE_TABLE(COL) VALUES (:RESULT);
END;
$$;
CALL caseExample2(6);
CALL caseExample2(4);
CALL caseExample2(10);
--** SSC-FDM-0007 - MISSING DEPENDENT OBJECT "CASE_TABLE" **
SELECT * FROM
CASE_TABLE;
|COL |
|-------------|
|Poor |
|No such grade|
|Excellent |
Problemas conhecidos¶
1. Labels are not supported in Snowflake Scripting CASE syntax¶
Os rótulos são comentados ou removidos, dependendo de sua posição.
EWIS relacionados¶
SSC-EWI-0094: Declaração de rótulo não suportada.
SSC-FDM-0007: Elemento com dependências ausentes.
COMPOUND STATEMENTS¶
Aviso
Esta seção é um trabalho em andamento, as informações podem mudar no futuro.
Nota
Algumas partes do código de saída foram omitidas por motivos de clareza.
Descrição geral¶
A unidade básica de um programa de código-fonte PL/SQL é o bloco, que agrupa instruções e declarações relacionadas.
Um bloco PL/SQL é definido pelas palavras-chave DECLARE, BEGIN, EXCEPTION e END. Essas palavras-chave dividem o bloco em uma parte declarativa, uma parte executável e uma parte de tratamento de exceções. Somente a parte executável é necessária. (Blocos anônimos PL/SQL)
O bloco BEGIN...END
no Oracle pode ter as seguintes características:
É aninhado.
Contém a instrução DECLARE para variáveis.
Agrupa várias instruções SQL ou PL/SQL.
Sintaxe do Oracle¶
[DECLARE <Variable declaration>]
BEGIN
<Executable statements>
[EXCEPTION <Exception handler>]
END
Sintaxe do Snowflake¶
BEGIN
<statement>;
[ <statement>; ... ]
[ EXCEPTION <exception_handler> ]
END;
Nota
No Snowflake, um bloco BEGIN/END pode ser a construção de nível superior dentro de um bloco anônimo (documentação do Snowflake).
Amostra de padrões da origem¶
1. IF-ELSE block¶
Consulte a seguinte documentação sobre as instruções IF para saber mais: Conversão de instruções SnowConvert IF e documentação da instrução Snowflake IF
Oracle¶
DECLARE
age NUMBER := 18;
BEGIN
IF age >= 18 THEN
DBMS_OUTPUT.PUT_LINE('You are an adult.');
ELSE
DBMS_OUTPUT.PUT_LINE('You are a minor.');
END IF;
END;
Statement processed.
You are an adult.
Snowflake¶
Aviso
Ao chamar um procedimento ou função definida pelo usuário (UDF), é necessário gerar código para suportar a equivalência como a variável call_results
. Nesse caso, é usado para imprimir as informações.
Revise a função definida pelo usuário (UDF) usada aqui.
DECLARE
age NUMBER(38, 18) := 18;
call_results VARIANT;
BEGIN
IF (:age >= 18) THEN
--** SSC-FDM-OR0035 - CHECK UDF IMPLEMENTATION FOR DBMS_OUTPUT.PUT_LINE_UDF. **
call_results := (
CALL DBMS_OUTPUT.PUT_LINE_UDF('You are an adult.')
);
ELSE
--** SSC-FDM-OR0035 - CHECK UDF IMPLEMENTATION FOR DBMS_OUTPUT.PUT_LINE_UDF. **
call_results := (
CALL DBMS_OUTPUT.PUT_LINE_UDF('You are a minor.')
);
END IF;
RETURN call_results;
END;
anonymous block
You are an adult.
2. CASE statement¶
Para obter mais informações, consulte a seguinte documentação: Documentação da instrução SnowConvert CASE e a documentação do Snowflake CASE
Oracle¶
BEGIN
DECLARE
day_of_week NUMBER := 3;
BEGIN
CASE day_of_week
WHEN 1 THEN DBMS_OUTPUT.PUT_LINE('Sunday');
WHEN 2 THEN DBMS_OUTPUT.PUT_LINE('Monday');
WHEN 3 THEN DBMS_OUTPUT.PUT_LINE('Tuesday');
WHEN 4 THEN DBMS_OUTPUT.PUT_LINE('Wednesday');
WHEN 5 THEN DBMS_OUTPUT.PUT_LINE('Thursday');
WHEN 6 THEN DBMS_OUTPUT.PUT_LINE('Friday');
WHEN 7 THEN DBMS_OUTPUT.PUT_LINE('Saturday');
ELSE DBMS_OUTPUT.PUT_LINE('Invalid day');
END CASE;
END;
END;
Statement processed.
Tuesday
Snowflake¶
Aviso
Ao chamar um procedimento ou função definida pelo usuário (UDF), é necessário gerar código para suportar a equivalência como a variável call_results
. Nesse caso, é usado para imprimir as informações.
Revise a função definida pelo usuário (UDF) usada aqui.
DECLARE
call_results VARIANT;
BEGIN
DECLARE
day_of_week NUMBER(38, 18) := 3;
BEGIN
CASE :day_of_week
WHEN 1 THEN
--** SSC-FDM-OR0035 - CHECK UDF IMPLEMENTATION FOR DBMS_OUTPUT.PUT_LINE_UDF. **
call_results := (
CALL DBMS_OUTPUT.PUT_LINE_UDF('Sunday')
);
WHEN 2 THEN
--** SSC-FDM-OR0035 - CHECK UDF IMPLEMENTATION FOR DBMS_OUTPUT.PUT_LINE_UDF. **
call_results := (
CALL DBMS_OUTPUT.PUT_LINE_UDF('Monday')
);
WHEN 3 THEN
--** SSC-FDM-OR0035 - CHECK UDF IMPLEMENTATION FOR DBMS_OUTPUT.PUT_LINE_UDF. **
call_results := (
CALL DBMS_OUTPUT.PUT_LINE_UDF('Tuesday')
);
WHEN 4 THEN
--** SSC-FDM-OR0035 - CHECK UDF IMPLEMENTATION FOR DBMS_OUTPUT.PUT_LINE_UDF. **
call_results := (
CALL DBMS_OUTPUT.PUT_LINE_UDF('Wednesday')
);
WHEN 5 THEN
--** SSC-FDM-OR0035 - CHECK UDF IMPLEMENTATION FOR DBMS_OUTPUT.PUT_LINE_UDF. **
call_results := (
CALL DBMS_OUTPUT.PUT_LINE_UDF('Thursday')
);
WHEN 6 THEN
--** SSC-FDM-OR0035 - CHECK UDF IMPLEMENTATION FOR DBMS_OUTPUT.PUT_LINE_UDF. **
call_results := (
CALL DBMS_OUTPUT.PUT_LINE_UDF('Friday')
);
WHEN 7 THEN
--** SSC-FDM-OR0035 - CHECK UDF IMPLEMENTATION FOR DBMS_OUTPUT.PUT_LINE_UDF. **
call_results := (
CALL DBMS_OUTPUT.PUT_LINE_UDF('Saturday')
);
ELSE
--** SSC-FDM-OR0035 - CHECK UDF IMPLEMENTATION FOR DBMS_OUTPUT.PUT_LINE_UDF. **
call_results := (
CALL DBMS_OUTPUT.PUT_LINE_UDF('Invalid day')
);
END CASE;
END;
RETURN call_results;
END;
anonymous block
Tuesday
3. LOOP statements¶
Para obter mais informações, consulte a documentação a seguir: SnowConvert FOR LOOP e Snowflake LOOP e documentação de FOR.
Oracle¶
BEGIN
FOR i IN 1..10 LOOP
NULL;
END LOOP;
END;
Statement processed.
Snowflake¶
BEGIN
FOR i IN 1 TO 10 LOOP
NULL;
END LOOP;
END;
anonymous block
4. Procedure call and OUTPUT parameters¶
O bloco anônimo no Oracle pode ter chamadas para procedimentos. Além disso, a documentação a seguir pode ser útil: Documentação de procedimento do SnowConvert.
O exemplo a seguir usa os parâmetros de OUT. As informações sobre a transformação atual podem ser encontradas aqui: Parâmetros do SnowConvert OUTPUT
Oracle¶
-- Procedure declaration
CREATE OR REPLACE PROCEDURE calculate_sum(
p_num1 IN NUMBER,
p_num2 IN NUMBER,
p_result OUT NUMBER
)
IS
BEGIN
-- Calculate the sum of the two numbers
p_result := p_num1 + p_num2;
END;
/
-- Anonymous block with a procedure call
DECLARE
-- Declare variables to hold the input and output values
v_num1 NUMBER := 10;
v_num2 NUMBER := 20;
v_result NUMBER;
BEGIN
-- Call the procedure with the input values and get the result
calculate_sum(v_num1, v_num2, v_result);
-- Display the result
DBMS_OUTPUT.PUT_LINE('The sum of ' || v_num1 || ' and ' || v_num2 || ' is ' || v_result);
END;
/
Statement processed.
The sum of 10 and 20 is 30
Snowflake¶
-- Procedure declaration
CREATE OR REPLACE PROCEDURE calculate_sum (p_num1 NUMBER(38, 18), p_num2 NUMBER(38, 18), p_result NUMBER(38, 18)
)
RETURNS VARIANT
LANGUAGE SQL
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},"attributes":{"component":"oracle"}}'
EXECUTE AS CALLER
AS
$$
BEGIN
-- Calculate the sum of the two numbers
p_result := :p_num1 + :p_num2;
RETURN p_result;
END;
$$;
-- Anonymous block with a procedure call
DECLARE
-- Declare variables to hold the input and output values
v_num1 NUMBER(38, 18) := 10;
v_num2 NUMBER(38, 18) := 20;
v_result NUMBER(38, 18);
call_results VARIANT;
BEGIN
call_results := (
CALL
-- Call the procedure with the input values and get the result
calculate_sum(:v_num1, :v_num2, :v_result)
);
v_result := :call_results;
-- Display the result
--** SSC-FDM-OR0035 - CHECK UDF IMPLEMENTATION FOR DBMS_OUTPUT.PUT_LINE_UDF. **
call_results := (
CALL DBMS_OUTPUT.PUT_LINE_UDF('The sum of ' || NVL(:v_num1 :: STRING, '') || ' and ' || NVL(:v_num2 :: STRING, '') || ' is ' || NVL(:v_result :: STRING, ''))
);
RETURN call_results;
END;
anonymous block
The sum of 10 and 20 is 30
5. Alter session¶
Para obter mais informações, consulte a documentação a seguir: Alterar a documentação da sessão.
Observe que, no Oracle, o bloco BEGIN...END
deve usar a instrução EXECUTE IMMEDIATE
para executar as instruções alter session
.
Oracle¶
DECLARE
lv_sql_txt VARCHAR2(200);
BEGIN
lv_sql_txt := 'ALTER SESSION SET nls_date_format = ''DD-MM-YYYY''';
EXECUTE IMMEDIATE lv_sql_txt;
END;
Statement processed.
Done
Snowflake¶
Aviso
O seguinte aviso poderá ser adicionado no futuro:\ /***MSC-WARNING - MSCEWI3058 - NLS_DATE_FORMAT SESSION PARAMETER DOES NOT ENFORCE THE INPUT FORMAT IN ORACLE***/
DECLARE
lv_sql_txt VARCHAR(200);
BEGIN
lv_sql_txt := 'ALTER SESSION SET nls_date_format = ''DD-MM-YYYY''';
!!!RESOLVE EWI!!! /*** SSC-EWI-0030 - THE STATEMENT BELOW HAS USAGES OF DYNAMIC SQL. ***/!!!!!!RESOLVE EWI!!! /*** SSC-EWI-0027 - THE FOLLOWING STATEMENT USES A VARIABLE/LITERAL WITH AN INVALID QUERY AND IT WILL NOT BE EXECUTED ***/!!!
EXECUTE IMMEDIATE :lv_sql_txt;
END;
anonymous block
Done
6. Cursors¶
O exemplo a seguir mostra o uso de um cursor
dentro de um bloco BEGIN...END
. Consulte a documentação a seguir para saber mais: Documentação de Cursor.
Oracle¶
CREATE TABLE employee (
ID_Number NUMBER,
emp_Name VARCHAR(200),
emp_Phone NUMBER
);
INSERT INTO employee VALUES (1, 'NameA NameZ', 1234567890);
INSERT INTO employee VALUES (2, 'NameB NameY', 1234567890);
DECLARE
var1 VARCHAR(20);
CURSOR cursor1 IS SELECT emp_Name FROM employee ORDER BY ID_Number;
BEGIN
OPEN cursor1;
FETCH cursor1 INTO var1;
CLOSE cursor1;
DBMS_OUTPUT.PUT_LINE(var1);
END;
Statement processed.
NameA NameZ
Snowflake¶
Aviso
Ao chamar um procedimento ou função definida pelo usuário (UDF), é necessário gerar código para suportar a equivalência como a variável call_results
. Nesse caso, é usado para imprimir as informações.
Revise a função definida pelo usuário (UDF) usada aqui.
CREATE OR REPLACE TABLE employee (
ID_Number NUMBER(38, 18) /*** SSC-FDM-0006 - NUMBER TYPE COLUMN MAY NOT BEHAVE SIMILARLY IN SNOWFLAKE. ***/,
emp_Name VARCHAR(200),
emp_Phone NUMBER(38, 18) /*** SSC-FDM-0006 - NUMBER TYPE COLUMN MAY NOT BEHAVE SIMILARLY IN SNOWFLAKE. ***/
)
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},"attributes":{"component":"oracle"}}'
;
INSERT INTO employee
VALUES (1, 'NameA NameZ', 1234567890);
INSERT INTO employee
VALUES (2, 'NameB NameY', 1234567890);
DECLARE
var1 VARCHAR(20);
cursor1 CURSOR
FOR
SELECT emp_Name FROM
employee
ORDER BY ID_Number;
call_results VARIANT;
BEGIN
OPEN cursor1;
FETCH cursor1 INTO
:var1;
CLOSE cursor1;
--** SSC-FDM-OR0035 - CHECK UDF IMPLEMENTATION FOR DBMS_OUTPUT.PUT_LINE_UDF. **
call_results := (
CALL DBMS_OUTPUT.PUT_LINE_UDF(:var1)
);
RETURN call_results;
END;
anonymous block
NameA NameZ
7. Select statements¶
Para obter mais informações, consulte a documentação a seguir: Documentação de Select.
Oracle¶
CREATE TABLE employee (
ID_Number NUMBER,
emp_Name VARCHAR(200),
emp_Phone NUMBER
);
INSERT INTO employee VALUES (1, 'NameA NameZ', 1234567890);
INSERT INTO employee VALUES (2, 'NameB NameY', 1234567890);
DECLARE
var_Result NUMBER;
BEGIN
SELECT COUNT(*) INTO var_Result FROM employee;
DBMS_OUTPUT.PUT_LINE(var_Result);
END;
Statement processed.
2
Snowflake¶
Aviso
Ao chamar um procedimento ou função definida pelo usuário (UDF), é necessário gerar código para suportar a equivalência como a variável call_results
. Nesse caso, é usado para imprimir as informações.
Revise a função definida pelo usuário (UDF) usada aqui.
CREATE OR REPLACE TABLE employee (
ID_Number NUMBER(38, 18) /*** SSC-FDM-0006 - NUMBER TYPE COLUMN MAY NOT BEHAVE SIMILARLY IN SNOWFLAKE. ***/,
emp_Name VARCHAR(200),
emp_Phone NUMBER(38, 18) /*** SSC-FDM-0006 - NUMBER TYPE COLUMN MAY NOT BEHAVE SIMILARLY IN SNOWFLAKE. ***/
)
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},"attributes":{"component":"oracle"}}'
;
INSERT INTO employee
VALUES (1, 'NameA NameZ', 1234567890);
INSERT INTO employee
VALUES (2, 'NameB NameY', 1234567890);
DECLARE
var_Result NUMBER(38, 18);
call_results VARIANT;
BEGIN
SELECT COUNT(*) INTO
:var_Result
FROM
employee;
--** SSC-FDM-OR0035 - CHECK UDF IMPLEMENTATION FOR DBMS_OUTPUT.PUT_LINE_UDF. **
call_results := (
CALL DBMS_OUTPUT.PUT_LINE_UDF(:var_Result)
);
RETURN call_results;
END;
anonymous block
2
8. Join Statements¶
Para obter mais informações, consulte a documentação a seguir: Documentação sobre junções.
Oracle¶
CREATE TABLE t1 (col1 INTEGER);
CREATE TABLE t2 (col1 INTEGER);
INSERT INTO t1 (col1) VALUES (2);
INSERT INTO t1 (col1) VALUES (3);
INSERT INTO t1 (col1) VALUES (4);
INSERT INTO t2 (col1) VALUES (1);
INSERT INTO t2 (col1) VALUES (2);
INSERT INTO t2 (col1) VALUES (2);
INSERT INTO t2 (col1) VALUES (3);
DECLARE
total_price FLOAT;
CURSOR cursor1 IS SELECT t1.col1 as FirstTable, t2.col1 as SecondTable
FROM t1 INNER JOIN t2
ON t2.col1 = t1.col1
ORDER BY 1,2;
BEGIN
total_price := 0.0;
FOR rec IN cursor1 LOOP
total_price := total_price + rec.FirstTable;
END LOOP;
DBMS_OUTPUT.PUT_LINE(total_price);
END;
Statement processed.
7
Snowflake¶
Aviso
Ao chamar um procedimento ou função definida pelo usuário (UDF), é necessário gerar código para suportar a equivalência como a variável call_results
. Nesse caso, é usado para imprimir as informações.
Revise a função definida pelo usuário (UDF) usada aqui.
CREATE OR REPLACE TABLE t1 (col1 INTEGER)
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},"attributes":{"component":"oracle"}}'
;
CREATE OR REPLACE TABLE t2 (col1 INTEGER)
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},"attributes":{"component":"oracle"}}'
;
INSERT INTO t1(col1) VALUES (2);
INSERT INTO t1(col1) VALUES (3);
INSERT INTO t1(col1) VALUES (4);
INSERT INTO t2(col1) VALUES (1);
INSERT INTO t2(col1) VALUES (2);
INSERT INTO t2(col1) VALUES (2);
INSERT INTO t2(col1) VALUES (3);
DECLARE
total_price FLOAT;
cursor1 CURSOR
FOR
SELECT t1.col1 as FIRSTTABLE, t2.col1 as SECONDTABLE
FROM
t1
INNER JOIN
t2
ON t2.col1 = t1.col1
ORDER BY 1,2;
call_results VARIANT;
BEGIN
total_price := 0.0;
OPEN cursor1;
--** SSC-PRF-0004 - THIS STATEMENT HAS USAGES OF CURSOR FOR LOOP **
FOR rec IN cursor1 DO
total_price :=
!!!RESOLVE EWI!!! /*** SSC-EWI-OR0036 - TYPES RESOLUTION ISSUES, ARITHMETIC OPERATION '+' MAY NOT BEHAVE CORRECTLY BETWEEN AproxNumeric AND unknown ***/!!!
:total_price + rec.FIRSTTABLE;
END FOR;
CLOSE cursor1;
--** SSC-FDM-OR0035 - CHECK UDF IMPLEMENTATION FOR DBMS_OUTPUT.PUT_LINE_UDF. **
call_results := (
CALL DBMS_OUTPUT.PUT_LINE_UDF(:total_price)
);
RETURN call_results;
END;
9. Exception handling¶
Oracle¶
DECLARE
v_result NUMBER;
BEGIN
v_result := 1 / 0;
EXCEPTION
WHEN ZERO_DIVIDE THEN
DBMS_OUTPUT.PUT_LINE( SQLERRM );
END;
Statement processed.
ORA-01476: divisor is equal to zero
Snowflake¶
Aviso
ZERO_DIVIDE
no Snowflake não é suportado.
DECLARE
v_result NUMBER(38, 18);
error_results VARIANT;
BEGIN
v_result := 1 / 0;
EXCEPTION
WHEN ZERO_DIVIDE THEN
--** SSC-FDM-OR0035 - CHECK UDF IMPLEMENTATION FOR DBMS_OUTPUT.PUT_LINE_UDF. **
error_results := (
CALL DBMS_OUTPUT.PUT_LINE_UDF( SQLERRM )
);
RETURN error_results;
END;
anonymous block
Division by zero
Problemas conhecidos¶
Instruções GOTO sem suporte no Oracle.
As exceções que usam instruções GOTO também podem ser afetadas.
A funcionalidade do cursor pode ser adaptada de acordo com as restrições atuais de conversão.
EWIs relacionados¶
SSC-EWI-0027:A instrução a seguir usa uma variável/literal com uma consulta inválida e não será executada.
SSC-EWI-OR0036: Problemas de resolução de tipos, a operação aritmética pode não se comportar corretamente entre string e date.
SSC-FDM-OR0035: DBMS_OUTPUT.PUTLINE verifique a implementação de UDF.
SSC-FDM-0006: A coluna de tipo de número pode não se comportar de forma semelhante no Snowflake.
SSC-PRF-0004: Essa instrução tem usos de cursor para loop.
SSC-EWI-0030: A instrução abaixo tem usos de SQL dinâmico
CONTINUE¶
Descrição¶
A instrução CONTINUE
encerra a iteração atual de um loop, condicional ou incondicionalmente, e transfere o controle para a próxima iteração do loop atual ou de um loop rotulado adjacente.\ (Instrução CONTINUE da referência de linguagem Oracle PL/SQL)
Nota
Algumas partes do código de saída foram omitidas por motivos de clareza.
CONTINUE [ label ] [ WHEN boolean_expression ] ;
{ CONTINUE | ITERATE } [ <label> ] ;
Amostra de padrões da origem¶
1. Simple Continue¶
O código ignora a instrução INSERT
usando CONTINUE
.
Esse caso é funcionalmente equivalente.
Oracle
CREATE TABLE continue_testing_table_1 (iterator VARCHAR2(5));
CREATE OR REPLACE PROCEDURE continue_procedure_1
IS
I NUMBER := 0;
J NUMBER := 20;
BEGIN
WHILE I <= J LOOP
I := I + 1;
CONTINUE;
INSERT INTO continue_testing_table_1
VALUES (TO_CHAR(I));
END LOOP;
END;
CALL continue_procedure_1();
SELECT * FROM continue_testing_table_1;
ITERATOR|
--------+
Snowflake Scripting
CREATE OR REPLACE TABLE continue_testing_table_1 (iterator VARCHAR(5))
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"oracle"}}'
;
CREATE OR REPLACE PROCEDURE continue_procedure_1 ()
RETURNS VARCHAR
LANGUAGE SQL
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"oracle"}}'
EXECUTE AS CALLER
AS
$$
DECLARE
I NUMBER(38, 18) := 0;
J NUMBER(38, 18) := 20;
BEGIN
WHILE (:I <= :J) LOOP
I := :I + 1;
CONTINUE;
INSERT INTO continue_testing_table_1
VALUES (TO_CHAR(:I));
END LOOP;
END;
$$;
CALL continue_procedure_1();
SELECT * FROM
continue_testing_table_1;
ITERATOR|
--------+
2. Continue with condition
O código ignora a inserção de números pares usando CONTINUE
.
Nota
Esse caso não é funcionalmente equivalente, mas você pode transformar a condição em uma instrução IF
.
Oracle¶
CREATE TABLE continue_testing_table_2 (iterator VARCHAR2(5));
CREATE OR REPLACE PROCEDURE continue_procedure_2
IS
I NUMBER := 0;
J NUMBER := 20;
BEGIN
WHILE I <= J LOOP
I := I + 1;
CONTINUE WHEN MOD(I,2) = 0;
INSERT INTO continue_testing_table_2 VALUES(TO_CHAR(I));
END LOOP;
END;
CALL continue_procedure_2();
SELECT * FROM continue_testing_table_2;
ITERATOR|
--------+
1 |
3 |
5 |
7 |
9 |
11 |
13 |
15 |
17 |
19 |
21 |
Script Snowflake¶
CREATE OR REPLACE TABLE continue_testing_table_2 (iterator VARCHAR(5))
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"oracle"}}'
;
CREATE OR REPLACE PROCEDURE continue_procedure_2 ()
RETURNS VARCHAR
LANGUAGE SQL
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"oracle"}}'
EXECUTE AS CALLER
AS
$$
DECLARE
I NUMBER(38, 18) := 0;
J NUMBER(38, 18) := 20;
BEGIN
WHILE (:I <= :J) LOOP
I := :I + 1;
IF (MOD(:I,2) = 0) THEN
CONTINUE;
END IF;
INSERT INTO continue_testing_table_2
VALUES(TO_CHAR(:I));
END LOOP;
END;
$$;
CALL continue_procedure_2();
SELECT * FROM
continue_testing_table_2;
ITERATOR|
--------+
1 |
3 |
5 |
7 |
9 |
11 |
13 |
15 |
17 |
19 |
21 |
3. Continue with label and condition¶
O código pula a linha 19 e o loop interno é executado apenas uma vez porque CONTINUE
está sempre pulando para o loop externo usando o rótulo.
Esse caso é funcionalmente equivalente à aplicação do mesmo processo da amostra anterior.
Nota
Observe que os rótulos serão comentados.
Oracle¶
CREATE OR REPLACE PROCEDURE continue_procedure_3
IS
I NUMBER := 0;
J NUMBER := 10;
K NUMBER := 0;
BEGIN
<<out_loop>>
WHILE I <= J LOOP
I := I + 1;
INSERT INTO continue_testing_table_3 VALUES('I' || TO_CHAR(I));
<<in_loop>>
WHILE K <= J * 2 LOOP
K := K + 1;
CONTINUE out_loop WHEN K > J / 2;
INSERT INTO continue_testing_table_3 VALUES('K' || TO_CHAR(K));
END LOOP in_loop;
K := 0;
END LOOP out_loop;
END;
CALL continue_procedure_3();
SELECT * FROM continue_testing_table_3;
ITERATOR|
--------+
I1 |
K1 |
K2 |
K3 |
K4 |
K5 |
I2 |
I3 |
I4 |
I5 |
I6 |
I7 |
I8 |
I9 |
I10 |
I11 |
Script Snowflake¶
CREATE OR REPLACE PROCEDURE continue_procedure_3 ()
RETURNS VARCHAR
LANGUAGE SQL
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"oracle"}}'
EXECUTE AS CALLER
AS
$$
DECLARE
I NUMBER(38, 18) := 0;
J NUMBER(38, 18) := 10;
K NUMBER(38, 18) := 0;
BEGIN
!!!RESOLVE EWI!!! /*** SSC-EWI-0094 - LABEL DECLARATION FOR A STATEMENT IS NOT SUPPORTED BY SNOWFLAKE SCRIPTING <<out_loop>> ***/!!!
WHILE (:I <= :J) LOOP
I := :I + 1;
INSERT INTO continue_testing_table_3
VALUES('I' || NVL(TO_CHAR(:I) :: STRING, ''));
!!!RESOLVE EWI!!! /*** SSC-EWI-0094 - LABEL DECLARATION FOR A STATEMENT IS NOT SUPPORTED BY SNOWFLAKE SCRIPTING <<in_loop>> ***/!!!
WHILE (:K <= :J * 2) LOOP
K := :K + 1;
IF (:K > :J / 2) THEN
CONTINUE out_loop;
END IF;
INSERT INTO continue_testing_table_3
VALUES('K' || NVL(TO_CHAR(:K) :: STRING, ''));
END LOOP in_loop;
K := 0;
END LOOP out_loop;
END;
$$;
CALL continue_procedure_3();
SELECT * FROM
continue_testing_table_3;
ITERATOR|
--------+
I1 |
K1 |
K2 |
K3 |
K4 |
K5 |
I2 |
I3 |
I4 |
I5 |
I6 |
I7 |
I8 |
I9 |
I10 |
I11 |
Problemas conhecidos¶
Não foram encontrados problemas.
EWIs relacionados¶
SSC-EWI-0094: Declaração de rótulo não suportada.
CREATE PROCEDURE¶
Descrição¶
Nota
Algumas partes do código de saída foram omitidas por motivos de clareza.
Um procedimento é um grupo de instruções PL/SQL que você pode chamar pelo nome. Uma especificação de chamada declara um método Java ou uma rotina de linguagem de terceira geração (3GL) para que possa ser chamada a partir de SQL e PL/SQL. A especificação de chamada informa ao Oracle Database qual método Java deve ser invocado quando uma chamada é feita. Ele também informa ao banco de dados quais conversões de tipo devem ser feitas para os argumentos e o valor de retorno. Procedimento Create da referência de linguagem Oracle SQL.
Para obter mais informações sobre o procedimento Oracle Create, veja aqui.
CREATE [ OR REPLACE ] [ EDITIONABLE | NONEDITIONABLE ]
PROCEDURE
[ schema. ] procedure_name
[ ( parameter_declaration [, parameter_declaration ]... ) ] [ sharing_clause ]
[ ( default_collation_option | invoker_rights_clause | accessible_by_clause)... ]
{ IS | AS } { [ declare_section ]
BEGIN statement ...
[ EXCEPTION exception_handler [ exception_handler ]... ]
END [ name ] ;
|
{ java_declaration | c_declaration } } ;
Para obter mais informações sobre o procedimento Snowflake Create, veja aqui.
CREATE [ OR REPLACE ] PROCEDURE <name> ( [ <arg_name> <arg_data_type> ] [ , ... ] )
RETURNS <result_data_type> [ NOT NULL ]
LANGUAGE SQL
[ { CALLED ON NULL INPUT | { RETURNS NULL ON NULL INPUT | STRICT } } ]
[ VOLATILE | IMMUTABLE ]
[ COMMENT = '<string_literal>' ]
[ EXECUTE AS { CALLER | OWNER } ]
AS '<procedure_definition>'
Amostra de padrões da origem¶
1. Basic Procedure¶
CREATE OR REPLACE PROCEDURE PROC1
IS
BEGIN
null;
END;
CREATE OR REPLACE PROCEDURE PROC1 ()
RETURNS VARCHAR
LANGUAGE SQL
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"oracle"}}'
EXECUTE AS CALLER
AS
$$
BEGIN
null;
END;
$$;
2. Procedure with Different Parameters¶
CREATE OR REPLACE PROCEDURE proc2
(
p1 OUT INTEGER,
p2 OUT INTEGER,
p3 INTEGER := 1,
p4 INTEGER DEFAULT 1
)
AS
BEGIN
p1 := 17;
p2 := 93;
END;
CREATE OR REPLACE PROCEDURE proc2
(p1 INTEGER, p2 INTEGER,
p3 INTEGER DEFAULT 1,
p4 INTEGER DEFAULT 1
)
RETURNS VARIANT
LANGUAGE SQL
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"oracle"}}'
EXECUTE AS CALLER
AS
$$
BEGIN
p1 := 17;
p2 := 93;
RETURN OBJECT_CONSTRUCT('p1', :p1, 'p2', :p2);
END;
$$;
Parâmetros de saída¶
O Snowflake não permite parâmetros de saída em procedimentos; uma maneira de simular esse comportamento poderia ser declarar uma variável e retornar seu valor no final do procedimento.
Parâmetros com valores padrão¶
O Snowflake não permite definir valores padrão para parâmetros em procedimentos; uma maneira de simular esse comportamento poderia ser declarar uma variável com o valor padrão ou sobrecarregar o procedimento.
3. Procedure with Additional Settings¶
CREATE OR REPLACE PROCEDURE proc3
DEFAULT COLLATION USING_NLS_COMP
AUTHID CURRENT_USER
AS
BEGIN
NULL;
END;
CREATE OR REPLACE PROCEDURE proc3 ()
RETURNS VARCHAR
LANGUAGE SQL
COMMENT = '{ "origin": "sf_sc", "name": "snowconvert", "version": { "major": 0, "minor": 0, "patch": "0" }, "attributes": { "component": "oracle", "convertedOn": "11/14/2024", "domain": "test" }}'
EXECUTE AS CALLER
AS
$$
BEGIN
NULL;
END;
$$;
4. Procedure with Basic Statements¶
CREATE OR REPLACE PROCEDURE proc4
(
param1 NUMBER
)
IS
localVar1 NUMBER;
countRows NUMBER;
tempSql VARCHAR(100);
tempResult NUMBER;
CURSOR MyCursor IS SELECT COL1 FROM Table1;
BEGIN
localVar1 := param1;
countRows := 0;
tempSql := 'SELECT COUNT(*) FROM Table1 WHERE COL1 =' || localVar1;
FOR myCursorItem IN MyCursor
LOOP
localVar1 := myCursorItem.Col1;
countRows := countRows + 1;
END LOOP;
INSERT INTO Table2 VALUES(countRows, 'ForCursor: Total Row count is: ' || countRows);
countRows := 0;
OPEN MyCursor;
LOOP
FETCH MyCursor INTO tempResult;
EXIT WHEN MyCursor%NOTFOUND;
countRows := countRows + 1;
END LOOP;
CLOSE MyCursor;
INSERT INTO Table2 VALUES(countRows, 'LOOP: Total Row count is: ' || countRows);
EXECUTE IMMEDIATE tempSql INTO tempResult;
IF tempResult > 0 THEN
INSERT INTO Table2 (COL1, COL2) VALUES(tempResult, 'Hi, found value:' || localVar1 || ' in Table1 -- There are ' || tempResult || ' rows');
COMMIT;
END IF;
END proc3;
CREATE OR REPLACE PROCEDURE proc4
(param1 NUMBER(38, 18)
)
RETURNS VARCHAR
LANGUAGE SQL
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},"attributes":{"component":"oracle"}}'
EXECUTE AS CALLER
AS
$$
DECLARE
localVar1 NUMBER(38, 18);
countRows NUMBER(38, 18);
tempSql VARCHAR(100);
tempResult NUMBER(38, 18);
MyCursor CURSOR
FOR
SELECT COL1 FROM
Table1;
BEGIN
localVar1 := :param1;
countRows := 0;
tempSql := 'SELECT COUNT(*) FROM
Table1
WHERE COL1 =' || NVL(:localVar1 :: STRING, '');
OPEN MyCursor;
--** SSC-PRF-0004 - THIS STATEMENT HAS USAGES OF CURSOR FOR LOOP **
FOR myCursorItem IN MyCursor DO
localVar1 := myCursorItem.Col1;
countRows := :countRows + 1;
END FOR;
CLOSE MyCursor;
INSERT INTO Table2
VALUES(:countRows, 'ForCursor: Total Row count is: ' || NVL(:countRows :: STRING, ''));
countRows := 0;
OPEN MyCursor;
LOOP
--** SSC-PRF-0003 - FETCH INSIDE A LOOP IS CONSIDERED A COMPLEX PATTERN, THIS COULD DEGRADE SNOWFLAKE PERFORMANCE. **
FETCH MyCursor INTO
:tempResult;
IF (tempResult IS NULL) THEN
EXIT;
END IF;
countRows := :countRows + 1;
END LOOP;
CLOSE MyCursor;
INSERT INTO Table2
SELECT
:countRows,
'LOOP: Total Row count is: ' || NVL(:countRows :: STRING, '');
!!!RESOLVE EWI!!! /*** SSC-EWI-0030 - THE STATEMENT BELOW HAS USAGES OF DYNAMIC SQL. ***/!!!
EXECUTE IMMEDIATE :tempSql
!!!RESOLVE EWI!!! /*** SSC-EWI-0058 - FUNCTIONALITY FOR 'EXECUTE IMMEDIATE RETURNING CLAUSE' IS NOT CURRENTLY SUPPORTED BY SNOWFLAKE SCRIPTING ***/!!!
INTO tempResult;
IF (:tempResult > 0) THEN
INSERT INTO Table2(COL1, COL2)
SELECT
:tempResult,
'Hi, found value:' || NVL(:localVar1 :: STRING, '') || ' in Table1 -- There are ' || NVL(:tempResult :: STRING, '') || ' rows';
--** SSC-FDM-OR0012 - COMMIT REQUIRES THE APPROPRIATE SETUP TO WORK AS INTENDED **
COMMIT;
END IF;
END;
$$;
5. Procedure with empty RETURN
statements¶
Nos procedimentos Oracle, você pode ter instruções RETURN
vazias para concluir a execução de um procedimento. No Snowflake Scripting, os procedimentos podem ter instruções RETURN
, mas devem ter um valor. Por padrão, todas as instruções vazias de RETURN
são convertidas com um valor de NULL
.
-- Procedure with empty return
CREATE OR REPLACE PROCEDURE MY_PROC
IS
BEGIN
NULL;
RETURN;
END;
-- Procedure with empty return
CREATE OR REPLACE PROCEDURE MY_PROC ()
RETURNS VARCHAR
LANGUAGE SQL
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"oracle"}}'
EXECUTE AS CALLER
AS
$$
BEGIN
NULL;
RETURN NULL;
END;
$$;
RETURN
em procedimentos com parâmetros de saída¶
Nos procedimentos com parâmetros de saída, em vez de um valor NULL
, um OBJECT_CONSTRUCT
será usado nas instruções vazias RETURN
para simular os parâmetros de saída no Snowflake Scripting.
CREATE OR REPLACE PROCEDURE PROC_WITH_OUTPUT_PARAMETERS (
param1 OUT NUMBER,
param2 OUT NUMBER,
param3 NUMBER
)
IS
BEGIN
IF param3 > 0 THEN
param1 := 2;
param2 := 1000;
RETURN;
END IF;
param1 := 5;
param2 := 3000;
END;
CREATE OR REPLACE PROCEDURE PROC_WITH_OUTPUT_PARAMETERS (param1 NUMBER(38, 18), param2 NUMBER(38, 18), param3 NUMBER(38, 18)
)
RETURNS VARIANT
LANGUAGE SQL
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"oracle"}}'
EXECUTE AS CALLER
AS
$$
BEGIN
IF (:param3 > 0) THEN
param1 := 2;
param2 := 1000;
RETURN OBJECT_CONSTRUCT('param1', :param1, 'param2', :param2);
END IF;
param1 := 5;
param2 := 3000;
RETURN OBJECT_CONSTRUCT('param1', :param1, 'param2', :param2);
END;
$$;
6. Procedure with DEFAULT parameters¶
DEFAULT permitem que os parâmetros nomeados sejam inicializados com valores padrão se nenhum valor for passado.
CREATE OR REPLACE PROCEDURE TEST(
X IN VARCHAR DEFAULT 'P',
Y IN VARCHAR DEFAULT 'Q'
)
AS
varX VARCHAR(32767) := NVL(X, 'P');
varY NUMBER := NVL(Y, 1);
BEGIN
NULL;
END TEST;
BEGIN
TEST(Y => 'Y');
END;
CREATE OR REPLACE PROCEDURE TEST (
X VARCHAR DEFAULT 'P',
Y VARCHAR DEFAULT 'Q'
)
RETURNS VARCHAR
LANGUAGE SQL
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"oracle"}}'
EXECUTE AS CALLER
AS
$$
DECLARE
varX VARCHAR(32767) := NVL(:X, 'P');
varY NUMBER(38, 18) := NVL(:Y, 1 :: STRING);
BEGIN
NULL;
END;
$$;
DECLARE
call_results VARIANT;
BEGIN
CALL
TEST(Y => 'Y');
RETURN call_results;
END;
Problemas conhecidos¶
1. Unsupported OUT parameters¶
Os procedimentos do Snowflake não têm uma opção nativa para parâmetros de saída.
2. Unsupported Oracle additional settings¶
As seguintes configurações e cláusulas do Oracle não são compatíveis com os procedimentos do Snowflake:
sharing_clause
default_collation_option
invoker_rights_clause
accessible_by_clause
java_declaration
c_declaration
EWIS relacionados¶
SSC-EWI-0058: No momento, a funcionalidade não é compatível com o Snowflake Scripting
SSC-EWI-OR0097: As propriedades dos procedimentos não são compatíveis com os procedimentos do Snowflake.
SSC-FDM-OR0012: As instruções COMMIT e ROLLBACK requerem uma configuração adequada para funcionar como pretendido.
SSC-PRF-0003: A busca dentro de um loop é considerada um padrão complexo, o que pode prejudicar o desempenho do Snowflake.
SSC-PRF-0004: Essa instrução tem usos de cursor para loop.
SSC-EWI-0030: A instrução abaixo tem usos de SQL dinâmico
DECLARE¶
Nota
Algumas partes do código de saída foram omitidas por motivos de clareza.
Descrição¶
A instrução Oracle DECLARE é uma parte opcional da instrução de bloco PL/SQL. Ele permite a criação de variáveis, constantes, instruções e definições de procedimentos, instruções e definições de funções, exceções, cursores, tipos e muitas outras instruções. Para obter mais informações sobre Oracle DECLARE, veja aqui.
declare_section body
declare_section::= { item_list_1 [ item_list_2 ] | item_list_2 }
item_list_1::=
{ type_definition
| cursor_declaration
| item_declaration
| function_declaration
| procedure_declaration
}
...
item_list_2::=
{ cursor_declaration
| cursor_definition
| function_declaration
| function_definition
| procedure_declaration
| procedure_definition
}
...
item_declaration::=
{ collection_variable_decl
| constant_declaration
| cursor_variable_declaration
| exception_declaration
| record_variable_declaration
| variable_declaration
}
body::= BEGIN statement ...
[ EXCEPTION exception_handler [ exception_handler ]... ] END [ name ] ;
[ DECLARE
{ <variable_declaration> | <cursor_declaration> | <exception_declaration> | <resultset_declaration> }
[, { <variable_declaration> | <cursor_declaration> | <exception_declaration> | <resultset_declaration> } ... ]
]
BEGIN
<statement>;
[ <statement>; ... ]
[ EXCEPTION <exception_handler> ]
END [ <label> ] ;
Amostra de padrões da origem¶
Declaração de variáveis¶
variable_declaration::=
variable datatype [ [ NOT NULL] {:= | DEFAULT} expression ] ;
<variable_name> <type>;
<variable_name> DEFAULT <expression> ;
<variable_name> <type> DEFAULT <expression> ;
Oracle¶
CREATE OR REPLACE PROCEDURE var_decl_proc
IS
var1 NUMBER;
var2 NUMBER := 1;
var3 NUMBER NOT NULL := 1;
var4 NUMBER DEFAULT 1;
var5 NUMBER NOT NULL DEFAULT 1;
BEGIN
NULL;
END;
Script Snowflake¶
CREATE OR REPLACE PROCEDURE var_decl_proc ()
RETURNS VARCHAR
LANGUAGE SQL
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"oracle"}}'
EXECUTE AS CALLER
AS
$$
DECLARE
var1 NUMBER(38, 18);
var2 NUMBER(38, 18) := 1;
var3 NUMBER(38, 18) := 1 /*** SSC-FDM-OR0025 - NOT NULL CONSTRAINT IS NOT SUPPORTED BY SNOWFLAKE ***/;
var4 NUMBER(38, 18) DEFAULT 1;
var5 NUMBER(38, 18) DEFAULT 1 /*** SSC-FDM-OR0025 - NOT NULL CONSTRAINT IS NOT SUPPORTED BY SNOWFLAKE ***/;
BEGIN
NULL;
END;
$$;
Declaração de constante¶
Aviso
As constantes não são compatíveis com o Snowflake Scripting; no entanto, elas estão sendo transformadas em variáveis para simular o comportamento.
constant_declaration::=
constant CONSTANT datatype [NOT NULL] { := | DEFAULT } expression ;
<variable_name> <type>;
<variable_name> DEFAULT <expression> ;
<variable_name> <type> DEFAULT <expression> ;
Oracle¶
CREATE OR REPLACE PROCEDURE const_decl_proc
IS
my_const1 CONSTANT NUMBER := 40;
my_const2 CONSTANT NUMBER NOT NULL := 40;
my_const2 CONSTANT NUMBER DEFAULT 40;
my_const2 CONSTANT NUMBER NOT NULL DEFAULT 40;
BEGIN
NULL;
END;
Script Snowflake¶
CREATE OR REPLACE PROCEDURE const_decl_proc ()
RETURNS VARCHAR
LANGUAGE SQL
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"oracle"}}'
EXECUTE AS CALLER
AS
$$
DECLARE
--** SSC-FDM-0016 - CONSTANTS ARE NOT SUPPORTED BY SNOWFLAKE SCRIPTING. IT WAS TRANSFORMED TO A VARIABLE **
my_const1 NUMBER(38, 18) := 40;
--** SSC-FDM-0016 - CONSTANTS ARE NOT SUPPORTED BY SNOWFLAKE SCRIPTING. IT WAS TRANSFORMED TO A VARIABLE **
--** SSC-FDM-OR0025 - NOT NULL CONSTRAINT IS NOT SUPPORTED BY SNOWFLAKE **
my_const2 NUMBER(38, 18) := 40;
--** SSC-FDM-0016 - CONSTANTS ARE NOT SUPPORTED BY SNOWFLAKE SCRIPTING. IT WAS TRANSFORMED TO A VARIABLE **
my_const2 NUMBER(38, 18) DEFAULT 40;
--** SSC-FDM-0016 - CONSTANTS ARE NOT SUPPORTED BY SNOWFLAKE SCRIPTING. IT WAS TRANSFORMED TO A VARIABLE **
--** SSC-FDM-OR0025 - NOT NULL CONSTRAINT IS NOT SUPPORTED BY SNOWFLAKE **
my_const2 NUMBER(38, 18) DEFAULT 40;
BEGIN
NULL;
END;
$$;
Declaração de cursor¶
cursor_declaration::= CURSOR cursor
[( cursor_parameter_dec [, cursor_parameter_dec ]... )]
RETURN rowtype;
cursor_parameter_dec::= parameter [IN] datatype [ { := | DEFAULT } expression ]
rowtype::=
{ {db_table_or_view | cursor | cursor_variable}%ROWTYPE
| record%TYPE
| record_type
}
<cursor_name> CURSOR [ ( <argument> [, <argument> ... ] ) ]
FOR <query> ;
A _ declaração de cursor _ do Oracle não é necessária, portanto, pode ser comentada no código de saída. A _ definição do cursor _ será usada em seu lugar e será convertida para a _ declaração de cursor _ do Snowflake Scripting. Consulte a seção CURSOR para obter mais informações sobre a definição de cursor.
Declaração de exceção
A declaração de exceção às vezes pode ser seguida pela inicialização da exceção; a transformação atual pega ambas e as mescla na declaração de exceção do Snowflake Scripting. O PRAGMA
EXCEPTION_INIT
original será comentado.
exception_declaration::= exception EXCEPTION;
PRAGMA EXCEPTION_INIT ( exception, error_code ) ;
<exception_name> EXCEPTION [ ( <exception_number> , '<exception_message>' ) ] ;
Oracle
CREATE OR REPLACE PROCEDURE procedure_exception
IS
my_exception EXCEPTION;
my_exception2 EXCEPTION;
PRAGMA EXCEPTION_INIT ( my_exception2, -20100 );
my_exception3 EXCEPTION;
PRAGMA EXCEPTION_INIT ( my_exception3, -19000 );
BEGIN
NULL;
END;
Snowflake Scripting
CREATE OR REPLACE PROCEDURE procedure_exception ()
RETURNS VARCHAR
LANGUAGE SQL
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},"attributes":{"component":"oracle"}}'
EXECUTE AS CALLER
AS
$$
DECLARE
my_exception EXCEPTION;
my_exception2 EXCEPTION (-20100, '');
!!!RESOLVE EWI!!! /*** SSC-EWI-OR0051 - PRAGMA EXCEPTION_INIT IS NOT SUPPORTED ***/!!!
PRAGMA EXCEPTION_INIT ( my_exception2, -20100 );
!!!RESOLVE EWI!!! /*** SSC-EWI-OR0099 - EXCEPTION CODE NUMBER EXCEEDS SNOWFLAKE SCRIPTING LIMITS ***/!!!
my_exception3 EXCEPTION;
!!!RESOLVE EWI!!! /*** SSC-EWI-OR0051 - PRAGMA EXCEPTION_INIT IS NOT SUPPORTED ***/!!!
PRAGMA EXCEPTION_INIT ( my_exception3, -19000 );
BEGIN
NULL;
END;
$$;
Casos não suportados
As seguintes instruções de declaração do Oracle não são compatíveis com o bloco de declaração do Snowflake Scripting:
Declaração de variável de cursor.
Declaração de variável de coleção.
Declaração de variável de registro.
Definição de tipo (todas as suas variantes).
Declaração e definição de funções.
Declaração e definição de procedimentos.
Known issues
1. The variable declarations with NOT NULL constraints are not supported by Snow Scripting.
A criação de variáveis com a restrição NOT NULL
gera um erro no Snow Scripting.
2. The cursor declaration has no equivalent to Snowflake Scripting.
A declaração de cursor Oracle é inútil, portanto, pode ser comentada no código de saída. Em vez disso, será usada a definição do cursor, que será convertida para a declaração de cursor do Snowflake Scripting.
3. The exception code exceeds Snowflake Scripting limits.
O código de exceção do Oracle está sendo removido quando excede os limites de código do Snowflake Scripting. O código de exceção deve ser um número inteiro entre -20000 e -20999.
3. The not supported cases.
Há algumas instruções de declaração do Oracle que não são compatíveis com o bloco de declaração do Snowflake Scripting, portanto, elas podem ser comentadas e um aviso será adicionado.
Related EWIS
SSC-EWI-OR0051: PRAGMA EXCEPTION_INIT não é compatível.
SSC-EWI-OR0099: O código de exceção excede o limite do Snowflake Scripting.
SSC-FDM-0016: As constantes não são compatíveis com o Snowflake Scripting. Ele foi transformado em uma variável.
SSC-FDM-OR0025: A restrição Not Null não é compatível com os procedimentos do Snowflake.
DEFAULT PARAMETERS
Nota
Algumas partes do código de saída foram omitidas por motivos de clareza.
Descrição¶
Um parâmetro padrão é um parâmetro que tem um valor caso um argumento não seja passado no procedimento ou na chamada de função. Como o Snowflake não oferece suporte a parâmetros padrão, o SnowConvert insere o valor padrão no procedimento ou na chamada de função.
Na declaração, a cláusula DEFAULT VALUE do parâmetro é removida. Ambas as sintaxes, o símbolo :=
e a cláusula DEFAULT
, são compatíveis.
Amostra de padrões da origem¶
Exemplo de código auxiliar¶
CREATE TABLE TABLE1(COL1 NUMBER, COL2 NUMBER);
CREATE TABLE TABLE2(COL1 NUMBER, COL2 NUMBER, COL2 NUMBER);0016
CREATE OR REPLACE TABLE TABLE1 (COL1 NUMBER(38, 18) /*** SSC-FDM-0006 - NUMBER TYPE COLUMN MAY NOT BEHAVE SIMILARLY IN SNOWFLAKE. ***/,
COL2 NUMBER(38, 18) /*** SSC-FDM-0006 - NUMBER TYPE COLUMN MAY NOT BEHAVE SIMILARLY IN SNOWFLAKE. ***/
)
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"oracle"}}'
;
CREATE OR REPLACE TABLE TABLE2 (COL1 NUMBER(38, 18) /*** SSC-FDM-0006 - NUMBER TYPE COLUMN MAY NOT BEHAVE SIMILARLY IN SNOWFLAKE. ***/,
COL2 NUMBER(38, 18) /*** SSC-FDM-0006 - NUMBER TYPE COLUMN MAY NOT BEHAVE SIMILARLY IN SNOWFLAKE. ***/,
COL2 NUMBER(38, 18) /*** SSC-FDM-0006 - NUMBER TYPE COLUMN MAY NOT BEHAVE SIMILARLY IN SNOWFLAKE. ***/
)
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"oracle"}}'
;
Declaração de parâmetro padrão¶
Oracle¶
CREATE OR REPLACE PROCEDURE PROC_WITH_DEFAULT_PARAMS1 (
param1 NUMBER,
param2 NUMBER default TO_NUMBER(1)
)
AS
BEGIN
INSERT INTO TABLE1 (COL1, COL2)
VALUES(param1, param2);
END;
CREATE OR REPLACE PROCEDURE PROC_WITH_DEFAULT_PARAMS2 (
param1 NUMBER default 1,
param2 NUMBER default 2
)
AS
BEGIN
INSERT INTO TABLE1 (COL1, COL2)
VALUES(param1, param2);
END;
CREATE OR REPLACE PROCEDURE PROCEDURE_WITH_DEAFAULT_PARAMS3 (
param1 NUMBER DEFAULT 100,
param2 NUMBER,
param3 NUMBER DEFAULT 1000
)
IS
BEGIN
INSERT INTO TABLE2(COL1, COL2, COL3)
VALUES (param1, param2, param3);
END;
Script Snowflake¶
CREATE OR REPLACE PROCEDURE PROC_WITH_DEFAULT_PARAMS1 (param1 NUMBER(38, 18),
param2 NUMBER(38, 18) DEFAULT TO_NUMBER(1)
)
RETURNS VARCHAR
LANGUAGE SQL
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"oracle"}}'
EXECUTE AS CALLER
AS
$$
BEGIN
INSERT INTO TABLE1(COL1, COL2)
VALUES(:param1, :param2);
END;
$$;
CREATE OR REPLACE PROCEDURE PROC_WITH_DEFAULT_PARAMS2 (
param1 NUMBER(38, 18) DEFAULT 1,
param2 NUMBER(38, 18) DEFAULT 2
)
RETURNS VARCHAR
LANGUAGE SQL
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"oracle"}}'
EXECUTE AS CALLER
AS
$$
BEGIN
INSERT INTO TABLE1(COL1, COL2)
VALUES(:param1, :param2);
END;
$$;
CREATE OR REPLACE PROCEDURE PROCEDURE_WITH_DEAFAULT_PARAMS3 (
param1 NUMBER(38, 18) DEFAULT 100, param2 NUMBER(38, 18),
param3 NUMBER(38, 18) DEFAULT 1000
)
RETURNS VARCHAR
LANGUAGE SQL
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"oracle"}}'
EXECUTE AS CALLER
AS
$$
BEGIN
INSERT INTO TABLE2(COL1, COL2, COL3)
VALUES (:param1, :param2, :param3);
END;
$$;
Chamada de procedimentos com parâmetros padrão¶
Oracle¶
CREATE OR REPLACE PROCEDURE PROC_WITH_DEFAULT_CALLS
AS
BEGIN
PROC_WITH_DEFAULT_PARAMS1(10, 15);
PROC_WITH_DEFAULT_PARAMS1(10);
PROC_WITH_DEFAULT_PARAMS2(10, 15);
PROC_WITH_DEFAULT_PARAMS2(10);
PROC_WITH_DEFAULT_PARAMS2();
END;
Script Snowflake¶
CREATE OR REPLACE PROCEDURE PROC_WITH_DEFAULT_CALLS ()
RETURNS VARCHAR
LANGUAGE SQL
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"oracle"}}'
EXECUTE AS CALLER
AS
$$
BEGIN
CALL
PROC_WITH_DEFAULT_PARAMS1(10, 15);
CALL
PROC_WITH_DEFAULT_PARAMS1(10);
CALL
PROC_WITH_DEFAULT_PARAMS2(10, 15);
CALL
PROC_WITH_DEFAULT_PARAMS2(10);
CALL
PROC_WITH_DEFAULT_PARAMS2();
END;
$$;
Para verificar se a funcionalidade está sendo emulada corretamente, a consulta a seguir executará o procedimento e um SELECT
da tabela mencionada anteriormente.
Oracle¶
CALL PROC_WITH_DEFAULT_CALLS();
SELECT * FROM TABLE1;
|COL1|COL2|
|----|----|
|10 |15 |
|10 |1 |
|10 |15 |
|10 |2 |
|1 |2 |
Script Snowflake¶
CALL PROC_WITH_DEFAULT_CALLS();
SELECT * FROM TABLE1;
|COL1|COL2|
|----|----|
|10 |15 |
|10 |1 |
|10 |15 |
|10 |2 |
|1 |2 |
Chamada de procedimentos com argumentos nomeados e parâmetros padrão¶
Oracle¶
CREATE OR REPLACE PROCEDURE PROC_WITH_DEFAULT_CALLS2
AS
BEGIN
PROCEDURE_WITH_DEAFAULT_PARAMS3(10, 20, 30);
PROCEDURE_WITH_DEAFAULT_PARAMS3(param1 => 10, param2 => 20, param3 => 30);
PROCEDURE_WITH_DEAFAULT_PARAMS3(param3 => 10, param1 => 20, param2 => 30);
PROCEDURE_WITH_DEAFAULT_PARAMS3(param3 => 10, param2 => 30);
PROCEDURE_WITH_DEAFAULT_PARAMS3(param2 => 10, param3 => 30);
PROCEDURE_WITH_DEAFAULT_PARAMS3(param2 => 10);
END;
Script Snowflake¶
CREATE OR REPLACE PROCEDURE PROC_WITH_DEFAULT_CALLS2 ()
RETURNS VARCHAR
LANGUAGE SQL
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"oracle"}}'
EXECUTE AS CALLER
AS
$$
BEGIN
CALL
PROCEDURE_WITH_DEAFAULT_PARAMS3(10, 20, 30);
CALL
PROCEDURE_WITH_DEAFAULT_PARAMS3(10, 20, 30);
CALL
PROCEDURE_WITH_DEAFAULT_PARAMS3(10, 20, 30);
CALL
PROCEDURE_WITH_DEAFAULT_PARAMS3(10, 30);
CALL
PROCEDURE_WITH_DEAFAULT_PARAMS3(10, 30);
CALL
PROCEDURE_WITH_DEAFAULT_PARAMS3(10);
END;
$$;
Para verificar se a funcionalidade está sendo emulada corretamente, a consulta a seguir executará o procedimento e um SELECT
da tabela mencionada anteriormente.
Oracle¶
CALL PROC_WITH_DEFAULT_CALLS2();
SELECT * FROM TABLE2;
|COL1|COL2|COL3|
|----|----|----|
|10 |20 |30 |
|10 |20 |30 |
|20 |30 |10 |
|100 |30 |10 |
|100 |10 |30 |
|100 |10 |1000|
Script Snowflake¶
CALL PROC_WITH_DEFAULT_CALLS2();
SELECT * FROM TABLE2;
|COL1|COL2|COL3|
|----|----|----|
|10 |20 |30 |
|10 |20 |30 |
|20 |30 |10 |
|100 |30 |10 |
|100 |10 |30 |
|100 |10 |1000|
Problemas conhecidos¶
1. Não foram encontrados problemas
EWIs relacionados¶
Sem EWIs relacionados.
EXECUTE IMMEDIATE¶
Descrição¶
A instrução EXECUTE
IMMEDIATE
cria e executa uma instrução dinâmica SQL em uma única operação.
O SQL dinâmico nativo usa a instrução EXECUTE
IMMEDIATE
para processar a maioria das instruções SQL dinâmicas. (Instrução EXECUTE IMMEDIATE da referência de linguagem Oracle PL/SQL)
EXECUTE IMMEDIATE <dynamic statement> [<additional clause> , ...];
dynamic statement::= { '<string literal>' | <variable> }
additional clauses::=
{ <into clause> [<using clause>]
| <bulk collect into clause> [<using clause>]
| <using clause> [<dynamic return clause>]
| <dynamic return clasue> }
O Snowflake Scripting tem suporte para essa instrução, embora com algumas diferenças funcionais. Para obter mais informações sobre a contraparte do Snowflake, visite a documentação do Snowflake EXECUTE IMMEDIATE.
EXECUTE IMMEDIATE <dynamic statement> ;
dynamic statement::= {'<string literal>' | <variable> | $<session variable>}
Amostra de padrões da origem¶
Os próximos exemplos criarão uma tabela e tentarão eliminar a tabela usando Execute Immediate.
Usando uma cadeia de caracteres codificada¶
Oracle¶
CREATE TABLE immediate_dropped_table(
col1 INTEGER
);
CREATE OR REPLACE PROCEDURE dropping_procedure
AS BEGIN
EXECUTE IMMEDIATE 'DROP TABLE immediate_dropped_table PURGE';
END;
CALL dropping_procedure();
SELECT * FROM immediate_dropped_table;
Script Snowflake¶
CREATE OR REPLACE TABLE immediate_dropped_table (
col1 INTEGER
)
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"oracle"}}'
;
CREATE OR REPLACE PROCEDURE dropping_procedure ()
RETURNS VARCHAR
LANGUAGE SQL
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"oracle"}}'
EXECUTE AS CALLER
AS
$$
BEGIN
!!!RESOLVE EWI!!! /*** SSC-EWI-0030 - THE STATEMENT BELOW HAS USAGES OF DYNAMIC SQL. ***/!!!
EXECUTE IMMEDIATE 'DROP TABLE immediate_dropped_table';
END;
$$;
CALL dropping_procedure();
SELECT * FROM
immediate_dropped_table;
Armazenando a cadeia de caracteres em uma variável¶
Oracle¶
CREATE TABLE immediate_dropped_table(
col1 INTEGER
);
CREATE OR REPLACE PROCEDURE dropping_procedure
AS
BEGIN
DECLARE
statement_variable VARCHAR2(500) := 'DROP TABLE immediate_dropped_table PURGE';
BEGIN
EXECUTE IMMEDIATE statement_variable;
END;
END;
CALL dropping_procedure();
SELECT * FROM immediate_dropped_table;
Script Snowflake¶
CREATE OR REPLACE TABLE immediate_dropped_table (
col1 INTEGER
)
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"oracle"}}'
;
CREATE OR REPLACE PROCEDURE dropping_procedure ()
RETURNS VARCHAR
LANGUAGE SQL
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"oracle"}}'
EXECUTE AS CALLER
AS
$$
BEGIN
DECLARE
statement_variable VARCHAR(500) := 'DROP TABLE immediate_dropped_table';
BEGIN
!!!RESOLVE EWI!!! /*** SSC-EWI-0030 - THE STATEMENT BELOW HAS USAGES OF DYNAMIC SQL. ***/!!!
EXECUTE IMMEDIATE :statement_variable;
END;
END;
$$;
CALL dropping_procedure();
SELECT * FROM
immediate_dropped_table;
Concatenação de parâmetros em instruções dinâmicas¶
Oracle¶
CREATE TABLE immediate_dropped_table(
col1 INTEGER
);
CREATE OR REPLACE PROCEDURE dropping_procedure(param1 VARCHAR2)
AS
BEGIN
DECLARE
statement_variable VARCHAR2(500) := 'DROP TABLE ' || param1 || ' PURGE';
BEGIN
EXECUTE IMMEDIATE statement_variable;
END;
END;
CALL dropping_procedure();
SELECT * FROM immediate_dropped_table;
Script Snowflake¶
CREATE OR REPLACE TABLE immediate_dropped_table (
col1 INTEGER
)
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"oracle"}}'
;
CREATE OR REPLACE PROCEDURE dropping_procedure (param1 VARCHAR)
RETURNS VARCHAR
LANGUAGE SQL
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"oracle"}}'
EXECUTE AS CALLER
AS
$$
BEGIN
DECLARE
statement_variable VARCHAR(500) := 'DROP TABLE ' || NVL(:param1 :: STRING, '');
BEGIN
!!!RESOLVE EWI!!! /*** SSC-EWI-0030 - THE STATEMENT BELOW HAS USAGES OF DYNAMIC SQL. ***/!!!
EXECUTE IMMEDIATE :statement_variable;
END;
END;
$$;
CALL dropping_procedure();
SELECT * FROM
immediate_dropped_table;
Transformação de cláusula USING¶
Oracle¶
CREATE TABLE immediate_inserted_table(COL1 INTEGER);
CREATE OR REPLACE PROCEDURE inserting_procedure_using(param1 INTEGER)
AS
BEGIN
EXECUTE IMMEDIATE 'INSERT INTO immediate_inserted_table VALUES (:1)' USING param1;
END;
CALL inserting_procedure_using(1);
SELECT * FROM immediate_inserted_table;
COL1|
----+
1|
Script Snowflake¶
Nota
Observe que são necessários parênteses para os parâmetros da cláusula USING no Snowflake Scripting.
CREATE OR REPLACE TABLE immediate_inserted_table (COL1 INTEGER)
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"oracle"}}'
;
CREATE OR REPLACE PROCEDURE inserting_procedure_using (param1 INTEGER)
RETURNS VARCHAR
LANGUAGE SQL
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"oracle"}}'
EXECUTE AS CALLER
AS
$$
BEGIN
!!!RESOLVE EWI!!! /*** SSC-EWI-0030 - THE STATEMENT BELOW HAS USAGES OF DYNAMIC SQL. ***/!!!
EXECUTE IMMEDIATE 'INSERT INTO immediate_inserted_table
VALUES (?)' USING ( param1);
END;
$$;
CALL inserting_procedure_using(1);
SELECT * FROM
immediate_inserted_table;
COL1|
----+
1|
Problemas conhecidos¶
1. Immediate Execution results cannot be stored in variables.¶
O SnowScripting não é compatível com as cláusulas INTO nem BULK COLLECT INTO. Por esse motivo, os resultados precisarão ser transmitidos por outros meios.
2. Numeric Placeholders¶
No momento, os nomes numéricos dos espaços reservados não estão sendo reconhecidos pelo SnowConvert, mas há um item de trabalho para corrigir esse problema.
3. Argument Expressions are not supported by Snowflake Scripting¶
No Oracle, é possível usar expressões como argumentos para a cláusula Using; no entanto, isso não é suportado pelo Snowflake Scripting, e elas são comentadas.
4. Dynamic SQL Execution queries may be marked incorrectly as non-runnable.¶
Em alguns cenários, uma instrução de execução pode ser comentada independentemente de ser segura ou não para ser executada, portanto, leve isso em consideração:
Oracle¶
CREATE OR REPLACE PROCEDURE inserting_procedure_variable_execute_concatenation_parameter(param1 INTEGER)
IS
query VARCHAR2(500) := 'INSERT INTO immediate_inserted_table VALUES (';
BEGIN
EXECUTE IMMEDIATE query || param1 || ')';
END;
Script Snowflake¶
Nota
Observe que são necessários parênteses para os parâmetros da cláusula USING no Snowflake Scripting.
CREATE OR REPLACE PROCEDURE inserting_procedure_variable_execute_concatenation_parameter (param1 INTEGER)
RETURNS VARCHAR
LANGUAGE SQL
EXECUTE AS CALLER
AS
$$
DECLARE
query VARCHAR(500) := 'INSERT INTO immediate_inserted_table VALUES (';
BEGIN
!!!RESOLVE EWI!!! /*** SSC-EWI-0030 - THE STATEMENT BELOW HAS USAGES OF DYNAMIC SQL. ***/!!!
!!!RESOLVE EWI!!! /*** SSC-EWI-0027 - THE FOLLOWING STATEMENT USES A VARIABLE/LITERAL WITH AN INVALID QUERY AND IT WILL NOT BE EXECUTED ***/!!!
EXECUTE IMMEDIATE NVL(:query :: STRING, '') || NVL(:param1 :: STRING, '') || ')';
END;
$$;
EWIs relacionados¶
SSC-EWI-0027: Variável com consulta inválida.
SSC-EWI-0030: A instrução abaixo tem usos de SQL dinâmico.
EXIT¶
Nota
Algumas partes do código de saída foram omitidas por motivos de clareza.
Descrição¶
A instrução EXIT
encerra a iteração atual de um loop, condicional ou incondicionalmente, e transfere o controle para o final do loop atual ou de um loop rotulado adjacente.\ (Instrução EXIT da referência de linguagem Oracle PL/SQL)
EXIT [ label ] [ WHEN boolean_expression ] ;
{ BREAK | EXIT } [ <label> ] ;
Amostra de padrões da origem¶
Nota
Observe que você pode alterar EXIT
com BREAK
e tudo funcionará da mesma forma.
1. Simple Exit¶
O código ignora a instrução INSERT
usando EXIT
.
Esse caso é funcionalmente equivalente.
Oracle
CREATE TABLE exit_testing_table_1 (
iterator VARCHAR2(5)
);
CREATE OR REPLACE PROCEDURE exit_procedure_1
IS
I NUMBER := 0;
J NUMBER := 20;
BEGIN
WHILE I <= J LOOP
I := I + 1;
EXIT;
INSERT INTO exit_testing_table_1 VALUES(TO_CHAR(I));
END LOOP;
END;
CALL exit_procedure_1();
SELECT * FROM exit_testing_table_1;
ITERATOR|
--------+
Snowflake Scripting
CREATE OR REPLACE TABLE exit_testing_table_1 (
iterator VARCHAR(5)
)
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"oracle"}}'
;
CREATE OR REPLACE PROCEDURE exit_procedure_1 ()
RETURNS VARCHAR
LANGUAGE SQL
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"oracle"}}'
EXECUTE AS CALLER
AS
$$
DECLARE
I NUMBER(38, 18) := 0;
J NUMBER(38, 18) := 20;
BEGIN
WHILE (:I <= :J) LOOP
I := :I + 1;
EXIT;
INSERT INTO exit_testing_table_1
VALUES(TO_CHAR(:I));
END LOOP;
END;
$$;
CALL exit_procedure_1();
SELECT * FROM
exit_testing_table_1;
ITERATOR|
--------+
2. Exit with condition
O código sai do loop quando o iterador é maior que 5.
Esse caso é funcionalmente equivalente a transformar a condição em uma instrução IF
.
Oracle¶
CREATE TABLE exit_testing_table_2 (
iterator VARCHAR2(5)
);
CREATE OR REPLACE PROCEDURE exit_procedure_2
IS
I NUMBER := 0;
J NUMBER := 20;
BEGIN
WHILE I <= J LOOP
EXIT WHEN I > 5;
I := I + 1;
INSERT INTO exit_testing_table_2 VALUES(TO_CHAR(I));
END LOOP;
END;
CALL exit_procedure_2();
SELECT * FROM exit_testing_table_2;
ITERATOR|
--------+
1 |
2 |
3 |
4 |
5 |
6 |
Script Snowflake¶
CREATE OR REPLACE TABLE exit_testing_table_2 (
iterator VARCHAR(5)
)
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"oracle"}}'
;
CREATE OR REPLACE PROCEDURE exit_procedure_2 ()
RETURNS VARCHAR
LANGUAGE SQL
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"oracle"}}'
EXECUTE AS CALLER
AS
$$
DECLARE
I NUMBER(38, 18) := 0;
J NUMBER(38, 18) := 20;
BEGIN
WHILE (:I <= :J) LOOP
IF (:I > 5) THEN
EXIT;
END IF;
I := :I + 1;
INSERT INTO exit_testing_table_2
VALUES(TO_CHAR(:I));
END LOOP;
END;
$$;
CALL exit_procedure_2();
SELECT * FROM
exit_testing_table_2;
ITERATOR|
--------+
1 |
2 |
3 |
4 |
5 |
6 |
3. Exit with label and condition¶
O código interrompe os dois loops usando a instrução EXIT
que aponta para o loop externo.
Esse caso é funcionalmente equivalente à aplicação do mesmo processo da amostra anterior.
Nota
Observe que os rótulos serão comentados.
Oracle¶
CREATE TABLE exit_testing_table_3 (
iterator VARCHAR2(5)
);
CREATE OR REPLACE PROCEDURE exit_procedure_3
IS
I NUMBER := 0;
J NUMBER := 10;
K NUMBER := 0;
BEGIN
<<out_loop>>
WHILE I <= J LOOP
I := I + 1;
INSERT INTO exit_testing_table_3 VALUES('I' || TO_CHAR(I));
<<in_loop>>
WHILE K <= J * 2 LOOP
K := K + 1;
EXIT out_loop WHEN K > J / 2;
INSERT INTO exit_testing_table_3 VALUES('K' || TO_CHAR(K));
END LOOP in_loop;
K := 0;
END LOOP out_loop;
END;
CALL exit_procedure_3();
SELECT * FROM exit_testing_table_3;
ITERATOR|
--------+
I1 |
K1 |
K2 |
K3 |
K4 |
K5 |
Script Snowflake¶
CREATE OR REPLACE TABLE exit_testing_table_3 (
iterator VARCHAR(5)
)
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"oracle"}}'
;
CREATE OR REPLACE PROCEDURE exit_procedure_3 ()
RETURNS VARCHAR
LANGUAGE SQL
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"oracle"}}'
EXECUTE AS CALLER
AS
$$
DECLARE
I NUMBER(38, 18) := 0;
J NUMBER(38, 18) := 10;
K NUMBER(38, 18) := 0;
BEGIN
!!!RESOLVE EWI!!! /*** SSC-EWI-0094 - LABEL DECLARATION FOR A STATEMENT IS NOT SUPPORTED BY SNOWFLAKE SCRIPTING <<out_loop>> ***/!!!
WHILE (:I <= :J) LOOP
I := :I + 1;
INSERT INTO exit_testing_table_3
VALUES('I' || NVL(TO_CHAR(:I) :: STRING, ''));
!!!RESOLVE EWI!!! /*** SSC-EWI-0094 - LABEL DECLARATION FOR A STATEMENT IS NOT SUPPORTED BY SNOWFLAKE SCRIPTING <<in_loop>> ***/!!!
WHILE (:K <= :J * 2) LOOP
K := :K + 1;
IF (:K > :J / 2) THEN
EXIT out_loop;
END IF;
INSERT INTO exit_testing_table_3
VALUES('K' || NVL(TO_CHAR(:K) :: STRING, ''));
END LOOP in_loop;
K := 0;
END LOOP out_loop;
END;
$$;
CALL exit_procedure_3();
SELECT * FROM
exit_testing_table_3;
ITERATOR|
--------+
I1 |
K1 |
K2 |
K3 |
K4 |
K5 |
Problemas conhecidos¶
Não foram encontrados problemas.
EWIs relacionados¶
SSC-EWI-0094: Declaração de rótulo não suportada.
EXPRESSIONS¶
Nota
Algumas partes do código de saída foram omitidas por motivos de clareza.
Descrição¶
A tabela a seguir apresenta um resumo de como transformar os diferentes tipos de Expressão Oracle no Snow Scripting.
Sintaxe |
Status da conversão |
Notas |
---|---|---|
Parcial |
||
Parcial |
||
Parcial |
||
Parcial |
||
Completo |
N/A |
|
Completo |
N/A |
|
Não convertido |
O Snowflake não tem um equivalente nativo para coleções Oracle. Consulte Coleções e registros. |
|
Não convertido |
O Snowflake não tem um equivalente nativo para os tipos de registro do Oracle. Consulte Coleções e registros. |
Cenários comuns parcialmente suportados¶
Constantes Oracle¶
Para obter mais informações, consulte a seção Declaração de constante Oracle.
Oracle¶
CREATE TABLE EXPRESSIONS_TABLE(col VARCHAR(30));
CREATE OR REPLACE PROCEDURE EXPRESSIONS_SAMPLE
IS
RESULT VARCHAR(50);
CONST CONSTANT VARCHAR(20) := 'CONSTANT TEXT';
BEGIN
-- CONSTANT EXPRESSIONS
RESULT := CONST;
INSERT INTO EXPRESSIONS_TABLE(COL) VALUES (RESULT);
END;
CALL EXPRESSIONS_SAMPLE();
SELECT * FROM EXPRESSIONS_TABLE;
|COL |
|-------------|
|CONSTANT TEXT|
Snowflake¶
CREATE OR REPLACE TABLE EXPRESSIONS_TABLE (col VARCHAR(30))
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"oracle"}}'
;
CREATE OR REPLACE PROCEDURE EXPRESSIONS_SAMPLE ()
RETURNS VARCHAR
LANGUAGE SQL
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"oracle"}}'
EXECUTE AS CALLER
AS
$$
DECLARE
RESULT VARCHAR(50);
--** SSC-FDM-0016 - CONSTANTS ARE NOT SUPPORTED BY SNOWFLAKE SCRIPTING. IT WAS TRANSFORMED TO A VARIABLE **
CONST VARCHAR(20) := 'CONSTANT TEXT';
BEGIN
-- CONSTANT EXPRESSIONS
RESULT := :CONST;
INSERT INTO EXPRESSIONS_TABLE(COL) VALUES (:RESULT);
END;
$$;
CALL EXPRESSIONS_SAMPLE();
SELECT * FROM
EXPRESSIONS_TABLE;
|COL |
|-------------|
|CONSTANT TEXT|
Expressões numéricas não suportadas¶
Oracle¶
CREATE TABLE NUMERIC_EXPRESSIONS_TABLE(col number);
CREATE OR REPLACE PROCEDURE NUMERIC_EXPRESSIONS
IS
RESULT NUMBER;
CURSOR C1 IS SELECT * FROM NUMERIC_EXPRESSIONS_TABLE;
TYPE NUMERIC_TABLE IS TABLE OF NUMBER(10);
COLLECTION NUMERIC_TABLE;
BEGIN
-- CURSOR EXPRESSIONS
OPEN C1;
RESULT := C1%ROWCOUNT;
CLOSE C1;
INSERT INTO NUMERIC_EXPRESSIONS_TABLE(COL) VALUES (RESULT);
-- ** OPERATOR
RESULT := 10 ** 2;
INSERT INTO NUMERIC_EXPRESSIONS_TABLE(COL) VALUES (RESULT);
-- COLLECTION EXPRESSIONS
COLLECTION := NUMERIC_TABLE(1, 2, 3, 4, 5, 6);
RESULT := COLLECTION.COUNT + COLLECTION.FIRST;
INSERT INTO NUMERIC_EXPRESSIONS_TABLE(COL) VALUES (RESULT);
-- IMPLICIT CURSOR EXPRESSIONS
UPDATE NUMERIC_EXPRESSIONS_TABLE SET COL = COL + 4;
RESULT := SQL%ROWCOUNT;
INSERT INTO NUMERIC_EXPRESSIONS_TABLE(COL) VALUES (RESULT);
END;
CALL NUMERIC_EXPRESSIONS();
SELECT * FROM NUMERIC_EXPRESSIONS_TABLE;
|COL|
|---|
|4 |
|104|
|11 |
|3 |
Expressões boolianas não suportadas¶
Oracle¶
--Aux function to convert BOOLEAN to VARCHAR
CREATE OR REPLACE FUNCTION convert_bool(p1 in BOOLEAN)
RETURN VARCHAR
AS
var1 VARCHAR(20) := 'FALSE';
BEGIN
IF p1 THEN
var1 := 'TRUE';
END IF;
RETURN var1;
END;
--Table
CREATE TABLE t_boolean_table
(
conditional_predicate VARCHAR(20),
collection_variable VARCHAR(20),
sql_variable VARCHAR(20)
)
--Main Procedure
CREATE OR REPLACE PROCEDURE p_boolean_limitations
AS
TYPE varray_example IS VARRAY(4) OF VARCHAR(15);
colection_example varray_example := varray_example('John', 'Mary', 'Alberto', 'Juanita');
collection_variable BOOLEAN;
conditional_predicate BOOLEAN;
sql_variable BOOLEAN;
--Result variables
col1 VARCHAR(20);
col2 VARCHAR(20);
col3 VARCHAR(20);
BEGIN
--Conditional predicate
conditional_predicate := INSERTING;
--Collection.EXISTS(index)
collection_variable := colection_example.EXISTS(2);
--Cursor FOUND / NOTFOUND / ISOPEN
sql_variable:= SQL%FOUND OR SQL%NOTFOUND OR SQL%ISOPEN;
--Convert BOOLEAN to VARCHAR to insert
col1 := convert_bool(conditional_predicate);
col2 := convert_bool(collection_variable);
col3 := convert_bool(sql_variable);
INSERT INTO t_boolean_table VALUES (col1, col2, col3);
END;
CALL p_boolean_limitations();
SELECT * FROM t_boolean_table;
EWIs Relacionados.¶
SSC-FDM-0016: As constantes não são compatíveis com o Snowflake Scripting. Ele foi transformado em uma variável.
FOR LOOP¶
Descrição¶
A cada iteração da instrução FOR
LOOP
, suas instruções são executadas, seu índice é incrementado ou decrementado e o controle retorna ao topo do loop. (Instrução FOR LOOP da referência de linguagem Oracle PL/SQL).
FOR
pls_identifier [ MUTABLE | IMMUTABLE ] [ constrained_type ]
[ , iterand_decl ]
IN
[ REVERSE ] iteration_control pred_clause_seq
[, qual_iteration_ctl]...
LOOP
statement...
END LOOP [ label ] ;
FOR <counter_variable> IN [ REVERSE ] <start> TO <end> { DO | LOOP }
statement;
[ statement; ... ]
END { FOR | LOOP } [ <label> ] ;
O Snowflake Scripting oferece suporte a FOR LOOP
que faz um loop de um número especificado de vezes. Os limites superior e inferior devem ser INTEGER
. Confira mais informações na documentação do Snowflake Scripting.
O comportamento do Oracle FOR LOOP
também pode ser modificado com o uso das instruções:
Amostra de padrões da origem¶
1. FOR LOOP¶
Esse caso é funcionalmente equivalente.
CREATE OR REPLACE PROCEDURE P1
AS
BEGIN
FOR i IN 1..10
LOOP
NULL;
END LOOP;
FOR i IN VAR1..VAR2
LOOP
NULL;
END LOOP;
FOR i IN REVERSE 1+2..10+5
LOOP
NULL;
END LOOP;
END;
CREATE OR REPLACE PROCEDURE P1 ()
RETURNS VARCHAR
LANGUAGE SQL
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"oracle"}}'
EXECUTE AS CALLER
AS
$$
BEGIN
FOR i IN 1 TO 10 LOOP
NULL;
END LOOP;
FOR i IN VAR1 TO VAR2 LOOP
NULL;
END LOOP;
FOR i IN REVERSE 1+2 TO 10+5 LOOP
NULL;
END LOOP;
END;
$$;
2. FOR LOOP with additional clauses
CREATE OR REPLACE PROCEDURE P2
AS
BEGIN
FOR i IN 1..10 WHILE i <= 5 LOOP
NULL;
END LOOP;
FOR i IN 5..15 BY 5 LOOP
NULL;
END LOOP;
END;
CREATE OR REPLACE PROCEDURE P2 ()
RETURNS VARCHAR
LANGUAGE SQL
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"oracle"}}'
EXECUTE AS CALLER
AS
$$
BEGIN
!!!RESOLVE EWI!!! /*** SSC-EWI-OR0101 - FOR LOOP WITH "WHILE" CLAUSE IS CURRENTLY NOT SUPPORTED BY SNOWFLAKE SCRIPTING ***/!!!
FOR i IN 1 TO 10 LOOP
NULL;
END LOOP;
!!!RESOLVE EWI!!! /*** SSC-EWI-OR0101 - FOR LOOP WITH "BY" CLAUSE IS CURRENTLY NOT SUPPORTED BY SNOWFLAKE SCRIPTING ***/!!!
FOR i IN 5 TO 15 LOOP
NULL;
END LOOP;
END;
$$;
3. FOR LOOP with multiple conditions
CREATE OR REPLACE PROCEDURE P3
AS
BEGIN
FOR i IN REVERSE 1..3,
REVERSE i+5..i+7
LOOP
NULL;
END LOOP;
END;
CREATE OR REPLACE PROCEDURE P3 ()
RETURNS VARCHAR
LANGUAGE SQL
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},"attributes":{"component":"oracle"}}'
EXECUTE AS CALLER
AS
$$
BEGIN
!!!RESOLVE EWI!!! /*** SSC-EWI-OR0100 - FOR LOOP WITH MULTIPLE CONDITIONS IS CURRENTLY NOT SUPPORTED BY SNOWFLAKE SCRIPTING ***/!!!
FOR i IN REVERSE 1 TO 3 LOOP
NULL;
END LOOP;
END;
$$;
4. FOR LOOP with unsupported format
CREATE OR REPLACE PROCEDURE P3
AS
TYPE values_aat IS TABLE OF PLS_INTEGER INDEX BY PLS_INTEGER;
l_employee_values values_aat;
BEGIN
FOR power IN REPEAT power*2 WHILE power <= 64 LOOP
NULL;
END LOOP;
FOR i IN VALUES OF l_employee_values LOOP
NULL;
END LOOP;
END;
CREATE OR REPLACE PROCEDURE P3 ()
RETURNS VARCHAR
LANGUAGE SQL
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},"attributes":{"component":"oracle"}}'
EXECUTE AS CALLER
AS
$$
DECLARE
-- !!!RESOLVE EWI!!! /*** SSC-EWI-0058 - FUNCTIONALITY FOR 'PL COLLECTION TYPE DEFINITION' IS NOT CURRENTLY SUPPORTED BY SNOWFLAKE SCRIPTING ***/!!!
-- TYPE values_aat IS TABLE OF PLS_INTEGER INDEX BY PLS_INTEGER;
l_employee_values VARIANT !!!RESOLVE EWI!!! /*** SSC-EWI-0062 - CUSTOM TYPE 'values_aat' USAGE CHANGED TO VARIANT ***/!!!;
BEGIN
!!!RESOLVE EWI!!! /*** SSC-EWI-OR0103 - FOR LOOP FORMAT IS CURRENTLY NOT SUPPORTED BY SNOWFLAKE SCRIPTING ***/!!!!!!RESOLVE EWI!!! /*** SSC-EWI-OR0101 - FOR LOOP WITH "WHILE" CLAUSE IS CURRENTLY NOT SUPPORTED BY SNOWFLAKE SCRIPTING ***/!!!
FOR power IN REPEAT power*2 WHILE power <= 64 LOOP
NULL;
END LOOP;
!!!RESOLVE EWI!!! /*** SSC-EWI-OR0103 - FOR LOOP FORMAT IS CURRENTLY NOT SUPPORTED BY SNOWFLAKE SCRIPTING ***/!!!
FOR i IN VALUES OF :l_employee_values LOOP
NULL;
END LOOP;
END;
$$;
Aviso
No momento, a transformação de tipos personalizados não é compatível com o Snowflake Scripting.
Problemas conhecidos¶
1. For With Multiple Conditions¶
O Oracle permite várias condições em um único FOR LOOP
. No entanto, o Snowflake Scripting permite apenas uma condição por FOR LOOP
. Somente a primeira condição é migrada e as outras são ignoradas durante a transformação. Consulte SSC-FDM-OR0022.
FOR i IN REVERSE 1..3,
REVERSE i+5..i+7
LOOP
NULL;
END LOOP;
--** SSC-FDM-OR0022 - FOR LOOP WITH MULTIPLE CONDITIONS IS CURRENTLY NOT SUPPORTED BY SNOWFLAKE SCRIPTING **
FOR i IN REVERSE 1 TO 3 LOOP
NULL;
END LOOP;
2. Variável de contador mutável vs. variável de contador imutável
O Oracle permite modificar o valor da variável FOR LOOP
dentro do loop. A documentação atual inclui essa funcionalidade, mas a Snowflake recomenda evitar isso. A modificação do valor dessa variável pode não se comportar corretamente no Snowflake Scripting.
3. Número inteiro vs. número flutuante para limite superior ou inferior
O Snowflake Scripting só permite um INTEGER
ou uma expressão que seja avaliada como INTEGER
como um limite para a condição FOR LOOP
. Os números flutuantes serão arredondados para cima ou para baixo e alterarão o limite original. Consulte SSC-EWI-OR0102.
4. Cláusulas Oracle não suportadas
A Oracle permite cláusulas adicionais para a condição FOR LOOP
. Como a cláusula BY para um incremento escalonado na condição. E a cláusula WHILE e WHEN para expressões boolianas. Essas cláusulas adicionais não são compatíveis com o Snowflake Scripting e são ignoradas durante a transformação. Verifique SSC-EWI-OR0101.
FOR i IN 5..15 BY 5 LOOP
NULL;
END LOOP;
!!!RESOLVE EWI!!! /*** SSC-EWI-OR0101 - FOR LOOP WITH "BY" CLAUSE IS CURRENTLY NOT SUPPORTED BY SNOWFLAKE SCRIPTING ***/!!!
FOR i IN 5 TO 15 LOOP
NULL;
END LOOP;
5. Formatos não suportados
O Oracle permite diferentes tipos de condições para um FOR LOOP
. Ele oferece suporte a expressões boolianas, coleções, registros… No entanto, os scripts do Snowflake suportam apenas FOR LOOP
com inteiros definidos como limites. Todos os outros formatos são marcados como não suportados e exigem esforço manual adicional para serem transformados. Consulte SSC-EWI-OR0103.
EWIs relacionados¶
SSC-EWI-0058: No momento, a funcionalidade não é compatível com o Snowflake Scripting.
SSC-EWI-0062: O uso do tipo personalizado foi alterado para variante.
SSC-EWI-OR0100: No momento, o Snowflake Scripting não é compatível com For Loop com várias condições. Apenas a primeira condição é usada.
SSC-EWI-OR0101: No momento, a cláusula específica For Loop não é compatível com o Snowflake Scripting.
SSC-EWI-OR0103: Atualmente, o formato For Loop não é compatível com o Snowflake Scripting.
FORALL¶
Descrição¶
A instrução FORALL
executa uma instrução DML várias vezes, com valores diferentes nas cláusulas VALUES
e WHERE
. (Instrução FORALL da referência de linguagem Oracle PL/SQL).
FORALL index IN bounds_clause [ SAVE ] [ EXCEPTIONS ] dml_statement ;
Aviso
O Snowflake Scripting não tem equivalência direta com a instrução FORALL
, mas pode ser emulado com diferentes soluções alternativas para obter equivalência funcional.
Amostra de padrões da origem¶
Dados de configuração¶
Oracle¶
CREATE TABLE table1 (
column1 NUMBER,
column2 NUMBER
);
INSERT INTO table1 (column1, column2) VALUES (1, 2);
INSERT INTO table1 (column1, column2) VALUES (2, 3);
INSERT INTO table1 (column1, column2) VALUES (3, 4);
INSERT INTO table1 (column1, column2) VALUES (4, 5);
INSERT INTO table1 (column1, column2) VALUES (5, 6);
CREATE TABLE table2 (
column1 NUMBER,
column2 NUMBER
);
INSERT INTO table2 (column1, column2) VALUES (1, 2);
CREATE TABLE error_table (
ORA_ERR_NUMBER$ NUMBER,
ORA_ERR_MESG$ VARCHAR2(2000),
ORA_ERR_ROWID$ ROWID,
ORA_ERR_OPTYP$ VARCHAR2(2),
ORA_ERR_TAG$ VARCHAR2(2000)
);
--departments
CREATE TABLE parent_table(
Id INT PRIMARY KEY,
Name VARCHAR2(10)
);
INSERT INTO parent_table VALUES (10, 'IT');
INSERT INTO parent_table VALUES (20, 'HR');
INSERT INTO parent_table VALUES (30, 'INFRA');
--employees
CREATE TABLE source_table(
Id INT PRIMARY KEY,
Name VARCHAR2(20) NOT NULL,
DepartmentID INT REFERENCES parent_table(Id)
);
INSERT INTO source_table VALUES (101, 'Anurag111111111', 10);
INSERT INTO source_table VALUES (102, 'Pranaya11111111', 20);
INSERT INTO source_table VALUES (103, 'Hina11111111111', 30);
--a copy of source
CREATE TABLE target_table(
Id INT PRIMARY KEY,
Name VARCHAR2(10) NOT NULL,
DepartmentID INT REFERENCES parent_table(Id)
);
INSERT INTO target_table VALUES (101, 'Anurag', 10);
Snowflake¶
CREATE OR REPLACE TABLE table1 (
column1 NUMBER(38, 18) /*** SSC-FDM-0006 - NUMBER TYPE COLUMN MAY NOT BEHAVE SIMILARLY IN SNOWFLAKE. ***/,
column2 NUMBER(38, 18) /*** SSC-FDM-0006 - NUMBER TYPE COLUMN MAY NOT BEHAVE SIMILARLY IN SNOWFLAKE. ***/
)
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"oracle"}}'
;
INSERT INTO table1(column1, column2) VALUES (1, 2);
INSERT INTO table1(column1, column2) VALUES (2, 3);
INSERT INTO table1(column1, column2) VALUES (3, 4);
INSERT INTO table1(column1, column2) VALUES (4, 5);
INSERT INTO table1(column1, column2) VALUES (5, 6);
CREATE OR REPLACE TABLE table2 (
column1 NUMBER(38, 18) /*** SSC-FDM-0006 - NUMBER TYPE COLUMN MAY NOT BEHAVE SIMILARLY IN SNOWFLAKE. ***/,
column2 NUMBER(38, 18) /*** SSC-FDM-0006 - NUMBER TYPE COLUMN MAY NOT BEHAVE SIMILARLY IN SNOWFLAKE. ***/
)
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"oracle"}}'
;
INSERT INTO table2(column1, column2) VALUES (1, 2);
CREATE OR REPLACE TABLE error_table (
"ORA_ERR_NUMBER$" NUMBER(38, 18) /*** SSC-FDM-0006 - NUMBER TYPE COLUMN MAY NOT BEHAVE SIMILARLY IN SNOWFLAKE. ***/,
"ORA_ERR_MESG$" VARCHAR(2000),
"ORA_ERR_ROWID$" VARCHAR(18) !!!RESOLVE EWI!!! /*** SSC-EWI-0036 - ROWID DATA TYPE CONVERTED TO VARCHAR ***/!!!,
"ORA_ERR_OPTYP$" VARCHAR(2),
"ORA_ERR_TAG$" VARCHAR(2000)
)
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"oracle"}}'
;
--departments
CREATE OR REPLACE TABLE parent_table (
Id INT PRIMARY KEY,
Name VARCHAR(10)
)
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"oracle"}}'
;
INSERT INTO parent_table
VALUES (10, 'IT');
INSERT INTO parent_table
VALUES (20, 'HR');
INSERT INTO parent_table
VALUES (30, 'INFRA');
--employees
CREATE OR REPLACE TABLE source_table (
Id INT PRIMARY KEY,
Name VARCHAR(20) NOT NULL,
DepartmentID INT REFERENCES parent_table (Id)
)
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"oracle"}}'
;
INSERT INTO source_table
VALUES (101, 'Anurag111111111', 10);
INSERT INTO source_table
VALUES (102, 'Pranaya11111111', 20);
INSERT INTO source_table
VALUES (103, 'Hina11111111111', 30);
--a copy of source
CREATE OR REPLACE TABLE target_table (
Id INT PRIMARY KEY,
Name VARCHAR(10) NOT NULL,
DepartmentID INT REFERENCES parent_table (Id)
)
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"oracle"}}'
;
INSERT INTO target_table
VALUES (101, 'Anurag', 10);
1. FORALL With Collection of Records¶
Oracle
Os três casos abaixo têm a mesma transformação para o Snowflake Scripting e são funcionalmente equivalentes.
CREATE OR REPLACE PROCEDURE myProcedure IS
CURSOR cursorVariable IS SELECT * FROM table1;
TYPE tableType IS TABLE OF cursorVariable%ROWTYPE;
tableVariable tableType;
BEGIN
OPEN cursorVariable;
LOOP
FETCH cursorVariable BULK COLLECT INTO tableVariable LIMIT 100;
EXIT WHEN tableVariable.COUNT = 0;
FORALL forIndex IN 1..tableVariable.COUNT
INSERT INTO table2 (column1, column2)
VALUES (tableVariable(forIndex).column1, tableVariable(forIndex).column2);
END LOOP;
CLOSE cursorVariable;
END;
COLUMN1| COLUMN2|
--------+--------+
1| 2|
1| 2|
2| 3|
3| 4|
4| 5|
5| 6|
Snowflake
CREATE OR REPLACE PROCEDURE myProcedure ()
RETURNS VARCHAR
LANGUAGE SQL
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"oracle"}}'
EXECUTE AS CALLER
AS
$$
BEGIN
--** SSC-PRF-0001 - THIS STATEMENT HAS USAGES OF CURSOR FETCH BULK OPERATIONS **
--** SSC-PRF-0003 - FETCH INSIDE A LOOP IS CONSIDERED A COMPLEX PATTERN, THIS COULD DEGRADE SNOWFLAKE PERFORMANCE. **
INSERT INTO table2(column1, column2)
(
SELECT
column1,
column2
FROM
table1
);
END;
$$;
COLUMN1| COLUMN2|
--------------------+-----------------------+
1.000000000000000000| 2.000000000000000000|
1.000000000000000000| 2.000000000000000000|
2.000000000000000000| 3.000000000000000000|
3.000000000000000000| 4.000000000000000000|
4.000000000000000000| 5.000000000000000000|
5.000000000000000000| 6.000000000000000000|
Nota
As instruções EWIs SSC-PRF-0001 e SSC-PRF-0003 são adicionadas em cada ocorrência de FETCH BULK COLLECT na instrução FORALL.
2. FORALL With INSERT INTO¶
Oracle¶
CREATE OR REPLACE PROCEDURE myProcedure IS
CURSOR cursorVariable IS
SELECT * FROM table1;
TYPE collectionTypeDefinition IS TABLE OF table1%ROWTYPE;
collectionVariable collectionTypeDefinition;
BEGIN
OPEN cursorVariable;
LOOP
FETCH cursorVariable BULK COLLECT INTO collectionVariable limit 2;
EXIT WHEN collectionVariable.COUNT = 0;
FORALL forIndex IN collectionVariable.FIRST..collectionVariable.LAST
INSERT INTO table2 VALUES collectionVariable(forIndex);
collectionVariable.DELETE;
END LOOP;
CLOSE cursorVariable;
END;
COLUMN1| COLUMN2|
--------+--------+
1| 2|
1| 2|
2| 3|
3| 4|
4| 5|
5| 6|
Snowflake¶
CREATE OR REPLACE PROCEDURE myProcedure ()
RETURNS VARCHAR
LANGUAGE SQL
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"oracle"}}'
EXECUTE AS CALLER
AS
$$
BEGIN
--** SSC-PRF-0001 - THIS STATEMENT HAS USAGES OF CURSOR FETCH BULK OPERATIONS **
--** SSC-PRF-0003 - FETCH INSIDE A LOOP IS CONSIDERED A COMPLEX PATTERN, THIS COULD DEGRADE SNOWFLAKE PERFORMANCE. **
INSERT INTO table2
(
SELECT
* FROM
table1
);
END;
$$;
COLUMN1| COLUMN2|
--------------------+-----------------------+
1.000000000000000000| 2.000000000000000000|
1.000000000000000000| 2.000000000000000000|
2.000000000000000000| 3.000000000000000000|
3.000000000000000000| 4.000000000000000000|
4.000000000000000000| 5.000000000000000000|
5.000000000000000000| 6.000000000000000000|
3. FORALL With Multiple Fetched Collections¶
Oracle¶
CREATE OR REPLACE PROCEDURE myProcedure IS
CURSOR cursorVariable IS
SELECT * FROM table1;
column1Collection dbms_sql.NUMBER_table;
column2Collection dbms_sql.NUMBER_table;
BEGIN
OPEN cursorVariable;
LOOP
FETCH cursorVariable BULK COLLECT INTO column1Collection, column2Collection limit 20;
EXIT WHEN column1Collection.COUNT = 0;
FORALL forIndex IN 1..column1Collection.COUNT
INSERT INTO table2 VALUES (
column1Collection(forIndex),
column2Collection(forIndex)
);
END LOOP;
CLOSE cursorVariable;
END;
CREATE OR REPLACE PROCEDURE myProcedure IS
CURSOR cursorVariable IS
SELECT * FROM table1;
column1Collection dbms_sql.NUMBER_table;
column2Collection dbms_sql.NUMBER_table;
BEGIN
OPEN cursorVariable;
LOOP
FETCH cursorVariable BULK COLLECT INTO column1Collection, column2Collection limit 2;
EXIT WHEN column1Collection.COUNT = 0;
FORALL forIndex IN 1..column1Collection.COUNT
UPDATE table2 SET column2 = column2Collection(forIndex)
WHERE column1 = column1Collection(forIndex);
END LOOP;
CLOSE cursorVariable;
END;
COLUMN1| COLUMN2|
--------+--------+
1| 2|
2| 3|
3| 4|
4| 5|
5| 6|
1| 2|
COLUMN1| COLUMN2|
--------+--------+
1| 2|
Snowflake¶
CREATE OR REPLACE PROCEDURE myProcedure ()
RETURNS VARCHAR
LANGUAGE SQL
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"oracle"}}'
EXECUTE AS CALLER
AS
$$
BEGIN
--** SSC-PRF-0001 - THIS STATEMENT HAS USAGES OF CURSOR FETCH BULK OPERATIONS **
--** SSC-PRF-0003 - FETCH INSIDE A LOOP IS CONSIDERED A COMPLEX PATTERN, THIS COULD DEGRADE SNOWFLAKE PERFORMANCE. **
INSERT INTO table2
(
SELECT
$1,
$2
FROM
table1
);
END;
$$;
CREATE OR REPLACE PROCEDURE myProcedure ()
RETURNS VARCHAR
LANGUAGE SQL
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"oracle"}}'
EXECUTE AS CALLER
AS
$$
BEGIN
--** SSC-PRF-0001 - THIS STATEMENT HAS USAGES OF CURSOR FETCH BULK OPERATIONS **
--** SSC-PRF-0003 - FETCH INSIDE A LOOP IS CONSIDERED A COMPLEX PATTERN, THIS COULD DEGRADE SNOWFLAKE PERFORMANCE. **
UPDATE table2
SET column2 = column1Collection.$2
FROM
(
SELECT
* FROM
table1) AS column1Collection
WHERE
column1 = column1Collection.$1;
END;
$$;
COLUMN1| COLUMN2|
--------------------+-----------------------+
1.000000000000000000| 2.000000000000000000|
1.000000000000000000| 2.000000000000000000|
2.000000000000000000| 3.000000000000000000|
3.000000000000000000| 4.000000000000000000|
4.000000000000000000| 5.000000000000000000|
5.000000000000000000| 6.000000000000000000|
COLUMN1| COLUMN2|
--------------------+-----------------------+
1.000000000000000000| 2.000000000000000000|
4. FORALL With Record of Collections¶
Oracle¶
CREATE OR REPLACE PROCEDURE myProcedure IS
CURSOR cursorVariable IS
SELECT * FROM table1;
TYPE recordType IS RECORD(
column1Collection dbms_sql.NUMBER_table,
column2Collection dbms_sql.NUMBER_table
);
columnRecord recordType;
BEGIN
OPEN cursorVariable;
LOOP
FETCH cursorVariable BULK COLLECT INTO columnRecord.column1Collection, columnRecord.column2Collection limit 20;
FORALL forIndex IN 1..columnRecord.column1Collection.COUNT
INSERT INTO table2 VALUES (
columnRecord.column1Collection(forIndex),
columnRecord.column2Collection(forIndex)
);
EXIT WHEN cursorVariable%NOTFOUND;
END LOOP;
CLOSE cursorVariable;
END;
COLUMN1| COLUMN2|
--------+--------+
1| 2|
1| 2|
2| 3|
3| 4|
4| 5|
5| 6|
Snowflake¶
CREATE OR REPLACE PROCEDURE myProcedure ()
RETURNS VARCHAR
LANGUAGE SQL
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"oracle"}}'
EXECUTE AS CALLER
AS
$$
BEGIN
--** SSC-PRF-0001 - THIS STATEMENT HAS USAGES OF CURSOR FETCH BULK OPERATIONS **
--** SSC-PRF-0003 - FETCH INSIDE A LOOP IS CONSIDERED A COMPLEX PATTERN, THIS COULD DEGRADE SNOWFLAKE PERFORMANCE. **
INSERT INTO table2
(
SELECT
$1,
$2
FROM
table1
);
END;
$$;
COLUMN1| COLUMN2|
--------------------+-----------------------+
1.000000000000000000| 2.000000000000000000|
1.000000000000000000| 2.000000000000000000|
2.000000000000000000| 3.000000000000000000|
3.000000000000000000| 4.000000000000000000|
4.000000000000000000| 5.000000000000000000|
5.000000000000000000| 6.000000000000000000|
5. FORALL With Dynamic SQL¶
Oracle¶
CREATE OR REPLACE PROCEDURE myProcedure IS
cursorVariable SYS_REFCURSOR;
TYPE collectionTypeDefinition IS
TABLE OF table1%ROWTYPE;
collectionVariable collectionTypeDefinition;
query VARCHAR(200) := 'SELECT * FROM table1';
BEGIN
OPEN cursorVariable FOR query;
LOOP
FETCH cursorVariable BULK COLLECT INTO collectionVariable;
EXIT WHEN collectionVariable.COUNT = 0;
FORALL forIndex IN collectionVariable.FIRST..collectionVariable.LAST
INSERT INTO table2 VALUES collectionVariable(forIndex);
collectionVariable.DELETE;
END LOOP;
CLOSE cursorVariable;
END;
COLUMN1| COLUMN2|
--------+--------+
1| 2|
1| 2|
2| 3|
3| 4|
4| 5|
5| 6|
Snowflake¶
CREATE OR REPLACE PROCEDURE myProcedure ()
RETURNS VARCHAR
LANGUAGE SQL
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"oracle"}}'
EXECUTE AS CALLER
AS
$$
DECLARE
query VARCHAR(200) := 'SELECT * FROM
table1';
BEGIN
--** SSC-PRF-0001 - THIS STATEMENT HAS USAGES OF CURSOR FETCH BULK OPERATIONS **
--** SSC-PRF-0003 - FETCH INSIDE A LOOP IS CONSIDERED A COMPLEX PATTERN, THIS COULD DEGRADE SNOWFLAKE PERFORMANCE. **
!!!RESOLVE EWI!!! /*** SSC-EWI-0030 - THE STATEMENT BELOW HAS USAGES OF DYNAMIC SQL. ***/!!!
EXECUTE IMMEDIATE 'CREATE OR REPLACE TEMPORARY TABLE query AS ' || :query;
INSERT INTO table2
(
SELECT
*
FROM
query
);
END;
$$;
COLUMN1| COLUMN2|
--------------------+-----------------------+
1.000000000000000000| 2.000000000000000000|
1.000000000000000000| 2.000000000000000000|
2.000000000000000000| 3.000000000000000000|
3.000000000000000000| 4.000000000000000000|
4.000000000000000000| 5.000000000000000000|
5.000000000000000000| 6.000000000000000000|
6. FORALL With Literal SQL¶
Oracle¶
CREATE OR REPLACE PROCEDURE SampleProcedure
IS
TYPE TabRecType IS RECORD (
column1 NUMBER,
column2 NUMBER
);
TYPE tabType IS TABLE OF TabRecType;
cursorRef SYS_REFCURSOR;
tab tabType;
BEGIN
OPEN cursorRef FOR 'SELECT src.column1, src.column2 FROM ' || 'table1' || ' src';
LOOP
BEGIN
FETCH cursorRef BULK COLLECT INTO tab LIMIT 1000;
FORALL i IN 1..tab.COUNT
INSERT INTO table2 (column1, column2)
VALUES (tab(i).column1, tab(i).column2);
EXIT WHEN cursorRef%NOTFOUND;
END;
END LOOP;
CLOSE cursorRef;
END;
COLUMN1| COLUMN2|
--------+--------+
1| 2|
1| 2|
2| 3|
3| 4|
4| 5|
5| 6|
Snowflake¶
CREATE OR REPLACE PROCEDURE SampleProcedure ()
RETURNS VARCHAR
LANGUAGE SQL
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"oracle"}}'
EXECUTE AS CALLER
AS
$$
BEGIN
EXECUTE IMMEDIATE 'CREATE OR REPLACE TEMPORARY TABLE cursorRef_TEMP_TABLE AS ' || 'SELECT src.column1, src.column2 FROM ' || 'table1' || ' src';
--** SSC-PRF-0001 - THIS STATEMENT HAS USAGES OF CURSOR FETCH BULK OPERATIONS **
--** SSC-PRF-0003 - FETCH INSIDE A LOOP IS CONSIDERED A COMPLEX PATTERN, THIS COULD DEGRADE SNOWFLAKE PERFORMANCE. **
INSERT INTO table2(column1, column2)
(
SELECT
*
FROM
cursorRef_TEMP_TABLE
);
END;
$$;
COLUMN1| COLUMN2|
--------+--------+
1| 2|
1| 2|
2| 3|
3| 4|
4| 5|
5| 6|
7. FORALL With Parametrized Cursors¶
Oracle¶
CREATE OR REPLACE PROCEDURE myProcedure IS
intVariable INTEGER := 7;
CURSOR cursorVariable(param1 INTEGER, param2 INTEGER default 5) IS
SELECT * FROM table1
WHERE
column2 = intVariable OR
column1 BETWEEN param1 AND param2;
TYPE collectionTypeDefinition IS
TABLE OF table1%ROWTYPE;
collectionVariable collectionTypeDefinition;
BEGIN
OPEN cursorVariable(1);
LOOP
FETCH cursorVariable BULK COLLECT INTO collectionVariable limit 20;
EXIT WHEN collectionVariable.COUNT = 0;
FORALL forIndex IN collectionVariable.FIRST..collectionVariable.LAST
INSERT INTO table2 VALUES collectionVariable(forIndex);
collectionVariable.DELETE;
END LOOP;
CLOSE cursorVariable;
END;
COLUMN1| COLUMN2|
--------+--------+
1| 2|
1| 2|
2| 3|
3| 4|
4| 5|
5| 6|
Snowflake¶
CREATE OR REPLACE PROCEDURE myProcedure ()
RETURNS VARCHAR
LANGUAGE SQL
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"oracle"}}'
EXECUTE AS CALLER
AS
$$
DECLARE
intVariable INTEGER := 7;
BEGIN
--** SSC-PRF-0001 - THIS STATEMENT HAS USAGES OF CURSOR FETCH BULK OPERATIONS **
--** SSC-PRF-0003 - FETCH INSIDE A LOOP IS CONSIDERED A COMPLEX PATTERN, THIS COULD DEGRADE SNOWFLAKE PERFORMANCE. **
INSERT INTO table2
(
SELECT
* FROM
table1
WHERE
column2 = :intVariable
OR
column1 BETWEEN 1 AND 5
);
END;
$$;
COLUMN1| COLUMN2|
--------+--------+
1| 2|
1| 2|
2| 3|
3| 4|
4| 5|
5| 6|
8. FORALL Without LOOPS¶
Oracle¶
CREATE OR REPLACE PROCEDURE myProcedure IS
TYPE collectionTypeDefinition IS TABLE OF table1%ROWTYPE;
collectionVariable collectionTypeDefinition;
BEGIN
SELECT * BULK COLLECT INTO collectionVariable FROM table1;
FORALL forIndex IN 1..collectionVariable.COUNT
INSERT INTO table2 VALUES (
collectionVariable (forIndex).column1,
collectionVariable (forIndex).column2
);
collectionVariable.DELETE;
END;
COLUMN1| COLUMN2|
--------+--------+
1| 2|
1| 2|
2| 3|
3| 4|
4| 5|
5| 6|
Snowflake¶
CREATE OR REPLACE PROCEDURE myProcedure ()
RETURNS VARCHAR
LANGUAGE SQL
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"oracle"}}'
EXECUTE AS CALLER
AS
$$
BEGIN
--** SSC-PRF-0003 - FETCH INSIDE A LOOP IS CONSIDERED A COMPLEX PATTERN, THIS COULD DEGRADE SNOWFLAKE PERFORMANCE. **
INSERT INTO table2
(
SELECT
column1,
column2
FROM
table1
);
END;
$$;
COLUMN1| COLUMN2|
--------------------+-----------------------+
1.000000000000000000| 2.000000000000000000|
1.000000000000000000| 2.000000000000000000|
2.000000000000000000| 3.000000000000000000|
3.000000000000000000| 4.000000000000000000|
4.000000000000000000| 5.000000000000000000|
5.000000000000000000| 6.000000000000000000|
9. FORALL With UPDATE Statements¶
Oracle¶
CREATE OR REPLACE PROCEDURE myProcedure IS
CURSOR cursorVariable IS
SELECT * FROM table1;
TYPE collectionTypeDefinition IS TABLE OF table1%ROWTYPE;
collectionVariable collectionTypeDefinition;
BEGIN
OPEN cursorVariable;
LOOP
FETCH cursorVariable BULK COLLECT INTO collectionVariable limit 2;
EXIT WHEN collectionVariable.COUNT = 0;
FORALL forIndex IN collectionVariable.FIRST..collectionVariable.LAST
UPDATE table2 SET column1 = '54321' WHERE column2 = collectionVariable(forIndex).column2;
collectionVariable.DELETE;
END LOOP;
CLOSE cursorVariable;
END;
COLUMN1| COLUMN2|
--------+--------+
54321| 2|
Snowflake¶
CREATE OR REPLACE PROCEDURE myProcedure ()
RETURNS VARCHAR
LANGUAGE SQL
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"oracle"}}'
EXECUTE AS CALLER
AS
$$
BEGIN
--** SSC-PRF-0001 - THIS STATEMENT HAS USAGES OF CURSOR FETCH BULK OPERATIONS **
--** SSC-PRF-0003 - FETCH INSIDE A LOOP IS CONSIDERED A COMPLEX PATTERN, THIS COULD DEGRADE SNOWFLAKE PERFORMANCE. **
UPDATE table2
SET column1 = '54321'
FROM
(
SELECT
* FROM
table1) AS collectionVariable
WHERE
column2 = collectionVariable.column2;
END;
$$;
COLUMN1| COLUMN2|
--------+--------+
54321| 2|
10. FORALL With DELETE Statements¶
Oracle¶
CREATE OR REPLACE PROCEDURE myProcedure IS
CURSOR cursorVariable IS
SELECT * FROM table1;
TYPE collectionTypeDefinition IS TABLE OF table1%ROWTYPE;
collectionVariable collectionTypeDefinition;
BEGIN
OPEN cursorVariable;
LOOP
FETCH cursorVariable BULK COLLECT INTO collectionVariable limit 2;
EXIT WHEN collectionVariable.COUNT = 0;
FORALL forIndex IN collectionVariable.FIRST..collectionVariable.LAST
DELETE FROM table2 WHERE column2 = collectionVariable(forIndex).column2;
collectionVariable.DELETE;
END LOOP;
CLOSE cursorVariable;
END;
no data found
Snowflake¶
CREATE OR REPLACE PROCEDURE myProcedure ()
RETURNS VARCHAR
LANGUAGE SQL
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"oracle"}}'
EXECUTE AS CALLER
AS
$$
BEGIN
--** SSC-PRF-0001 - THIS STATEMENT HAS USAGES OF CURSOR FETCH BULK OPERATIONS **
--** SSC-PRF-0003 - FETCH INSIDE A LOOP IS CONSIDERED A COMPLEX PATTERN, THIS COULD DEGRADE SNOWFLAKE PERFORMANCE. **
DELETE FROM
table2
USING (
SELECT
* FROM
table1) collectionVariable
WHERE
table2.column2 = collectionVariable.column2;
END;
$$;
Query produced no results
11. FORALL With PACKAGE References¶
Oracle¶
CREATE OR REPLACE PACKAGE MyPackage AS
TYPE collectionTypeDefinition IS
TABLE OF table1%ROWTYPE;
collectionVariable collectionTypeDefinition;
END;
/
CREATE OR REPLACE PROCEDURE InsertIntoPackage(param integer) IS
BEGIN
SELECT
param,
param BULK COLLECT INTO MyPackage.collectionVariable
FROM
DUAL;
END;
/
CREATE OR REPLACE PROCEDURE InsertUsingPackage IS
BEGIN
FORALL forIndex IN MyPackage.collectionVariable.FIRST..MyPackage.collectionVariable.LAST
INSERT INTO table2 VALUES MyPackage.collectionVariable(forIndex);
MyPackage.collectionVariable.DELETE;
END;
/
DECLARE
param_value INTEGER := 10;
BEGIN
InsertIntoPackage(param_value);
InsertUsingPackage;
END;
select * from table2;
COLUMN1| COLUMN2|
--------+--------+
1| 2|
10| 10|
Snowflake¶
CREATE SCHEMA IF NOT EXISTS MyPackage
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"oracle"}}'
;
!!!RESOLVE EWI!!! /*** SSC-EWI-OR0049 - PACKAGE TYPE DEFINITIONS in stateful package MyPackage are not supported yet ***/!!!
TYPE collectionTypeDefinition IS
TABLE OF table1%ROWTYPE;
CREATE OR REPLACE TEMPORARY TABLE MYPACKAGE_COLLECTIONVARIABLE (
);
CREATE OR REPLACE PROCEDURE InsertIntoPackage (param integer)
RETURNS VARCHAR
LANGUAGE SQL
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"oracle"}}'
EXECUTE AS CALLER
AS
$$
BEGIN
DELETE FROM
MYPACKAGE_COLLECTIONVARIABLE;
INSERT INTO MYPACKAGE_COLLECTIONVARIABLE
(
SELECT
:param,
:param
FROM
DUAL
);
END;
$$;
CREATE OR REPLACE PROCEDURE InsertUsingPackage ()
RETURNS VARCHAR
LANGUAGE SQL
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"oracle"}}'
EXECUTE AS CALLER
AS
$$
BEGIN
--** SSC-PRF-0003 - FETCH INSIDE A LOOP IS CONSIDERED A COMPLEX PATTERN, THIS COULD DEGRADE SNOWFLAKE PERFORMANCE. **
INSERT INTO table2
(
SELECT
*
FROM
MYPACKAGE_COLLECTIONVARIABLE
);
END;
$$;
DECLARE
param_value INTEGER := 10;
call_results VARIANT;
BEGIN
CALL
InsertIntoPackage(:param_value);
CALL
InsertUsingPackage();
RETURN call_results;
END;
select * from
table2;
COLUMN1| COLUMN2|
---------------------+-----------------------+
1.000000000000000000| 2.000000000000000000|
10.000000000000000000| 10.000000000000000000|
Aviso
A transformação acima só funciona se a variável definida no pacote for um registro de coleções.
12. FORALL With MERGE Statements¶
Oracle¶
CREATE OR REPLACE PROCEDURE myProcedure IS
CURSOR cursorVariable IS
SELECT * FROM table1;
TYPE collectionTypeDefinition IS
TABLE OF table1%ROWTYPE;
collectionVariable collectionTypeDefinition;
BEGIN
OPEN cursorVariable;
LOOP
FETCH cursorVariable BULK COLLECT INTO collectionVariable limit 2;
EXIT WHEN collectionVariable.COUNT = 0;
FORALL forIndex IN collectionVariable.FIRST..collectionVariable.LAST
MERGE INTO table2 tgt
USING (
SELECT
collectionVariable(forIndex).column1 column1,
collectionVariable(forIndex).column2 column2
FROM DUAL
) src
ON (tgt.column1 = src.column1)
WHEN MATCHED THEN
UPDATE SET
tgt.column2 = src.column2 * 2
WHEN NOT MATCHED THEN
INSERT (column1, column2)
VALUES (src.column1, src.column2);
END LOOP;
CLOSE cursorVariable;
END;
COLUMN1| COLUMN2|
--------+--------+
1| 4|
2| 3|
3| 4|
4| 5|
5| 6|
Snowflake¶
CREATE OR REPLACE PROCEDURE myProcedure ()
RETURNS VARCHAR
LANGUAGE SQL
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"oracle"}}'
EXECUTE AS CALLER
AS
$$
BEGIN
--** SSC-PRF-0001 - THIS STATEMENT HAS USAGES OF CURSOR FETCH BULK OPERATIONS **
--** SSC-PRF-0003 - FETCH INSIDE A LOOP IS CONSIDERED A COMPLEX PATTERN, THIS COULD DEGRADE SNOWFLAKE PERFORMANCE. **
MERGE INTO table2 tgt
USING (
SELECT
collectionVariable.column1 column1,
collectionVariable.column2 column2
FROM
(
SELECT
* FROM
table1
) collectionVariable
) src
ON (tgt.column1 = src.column1)
WHEN MATCHED THEN
UPDATE SET
tgt.column2 = src.column2 * 2
WHEN NOT MATCHED THEN
INSERT (column1, column2)
VALUES (src.column1, src.column2);
END;
$$;
COLUMN1| COLUMN2|
--------------------+-----------------------+
2.000000000000000000| 3.000000000000000000|
3.000000000000000000| 4.000000000000000000|
4.000000000000000000| 5.000000000000000000|
5.000000000000000000| 6.000000000000000000|
1.000000000000000000| 4.000000000000000000|
Aviso
A transformação acima só funciona se a instrução SELECT
dentro de MERGE
estiver selecionando da tabela DUAL
.
13. Default FORALL transformation¶
Nota
Talvez você também se interesse por Auxiliares de cursor em massa.
Oracle¶
CREATE OR REPLACE PROCEDURE myProcedure IS
CURSOR cursorVariable IS SELECT * FROM table1;
TYPE columnsRecordType IS RECORD (column1 dbms_sql.NUMBER_table, column2 dbms_sql.NUMBER_table);
recordVariable columnsRecordType;
TYPE collectionTypeDefinition IS TABLE OF table1%ROWTYPE;
collectionVariable collectionTypeDefinition;
col1 dbms_sql.NUMBER_table;
col2 dbms_sql.NUMBER_table;
BEGIN
OPEN cursorVariable;
FETCH cursorVariable BULK COLLECT INTO collectionVariable limit 2;
FORALL forIndex IN collectionVariable.FIRST..collectionVariable.LAST
INSERT INTO table2 (column1, column2)
VALUES (collectionVariable(forIndex).column1, collectionVariable(forIndex).column2);
FETCH cursorVariable BULK COLLECT INTO col1, col2 limit 2;
FORALL forIndex IN col1.FIRST..col1.LAST
INSERT INTO table2 (column1, column2)
VALUES (col1(forIndex), col2(forIndex));
LOOP
FETCH cursorVariable BULK COLLECT INTO recordVariable limit 2;
EXIT WHEN recordVariable.column1.COUNT = 0;
FORALL forIndex IN recordVariable.column1.FIRST..recordVariable.column1.LAST
INSERT INTO table2 (column1, column2)
VALUES (recordVariable.column1(forIndex), recordVariable.column2(forIndex));
END LOOP;
CLOSE cursorVariable;
END;
COLUMN1| COLUMN2|
--------+--------+
1| 2|
1| 2|
2| 3|
3| 4|
4| 5|
5| 6|
Snowflake¶
CREATE OR REPLACE PROCEDURE myProcedure ()
RETURNS VARCHAR
LANGUAGE SQL
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},"attributes":{"component":"oracle"}}'
EXECUTE AS CALLER
AS
$$
DECLARE
cursorVariable OBJECT := INIT_CURSOR_UDF('cursorVariable', ' SELECT * FROM
table1');
!!!RESOLVE EWI!!! /*** SSC-EWI-0056 - CUSTOM TYPES ARE NOT SUPPORTED IN SNOWFLAKE BUT REFERENCES TO THIS CUSTOM TYPE WERE CHANGED TO OBJECT ***/!!!
TYPE columnsRecordType IS RECORD (column1 dbms_sql.NUMBER_table, column2 dbms_sql.NUMBER_table);
recordVariable OBJECT !!!RESOLVE EWI!!! /*** SSC-EWI-0036 - columnsRecordType DATA TYPE CONVERTED TO OBJECT ***/!!! := OBJECT_CONSTRUCT();
-- !!!RESOLVE EWI!!! /*** SSC-EWI-0058 - FUNCTIONALITY FOR 'PL COLLECTION TYPE DEFINITION' IS NOT CURRENTLY SUPPORTED BY SNOWFLAKE SCRIPTING ***/!!!
-- TYPE collectionTypeDefinition IS TABLE OF table1%ROWTYPE;
collectionVariable VARIANT !!!RESOLVE EWI!!! /*** SSC-EWI-0062 - CUSTOM TYPE 'collectionTypeDefinition' USAGE CHANGED TO VARIANT ***/!!!;
col1 VARIANT /*** SSC-FDM-0015 - REFERENCED CUSTOM TYPE 'dbms_sql.NUMBER_table' IN QUERY NOT FOUND, USAGES MAY BE AFFECTED ***/;
col2 VARIANT /*** SSC-FDM-0015 - REFERENCED CUSTOM TYPE 'dbms_sql.NUMBER_table' IN QUERY NOT FOUND, USAGES MAY BE AFFECTED ***/;
FORALL INTEGER;
BEGIN
cursorVariable := (
CALL OPEN_BULK_CURSOR_UDF(:cursorVariable)
);
--** SSC-PRF-0001 - THIS STATEMENT HAS USAGES OF CURSOR FETCH BULK OPERATIONS **
cursorVariable := (
CALL FETCH_BULK_COLLECTION_RECORDS_UDF(:cursorVariable, 2)
);
collectionVariable := :cursorVariable:RESULT;
FORALL := ARRAY_SIZE(:collectionVariable);
INSERT INTO table2(column1, column2)
(
SELECT
:collectionVariable[forIndex]:column1,
: collectionVariable[forIndex]:column2
FROM
(
SELECT
seq4() AS forIndex
FROM
TABLE(GENERATOR(ROWCOUNT => :FORALL))
)
);
--** SSC-PRF-0001 - THIS STATEMENT HAS USAGES OF CURSOR FETCH BULK OPERATIONS **
cursorVariable := (
CALL FETCH_BULK_COLLECTIONS_UDF(:cursorVariable, 2)
);
col1 := :cursorVariable:RESULT[0];
col2 := :cursorVariable:RESULT[1];
FORALL := ARRAY_SIZE(:col1);
INSERT INTO table2(column1, column2)
(
SELECT
:col1[forIndex],
: col2[forIndex]
FROM
(
SELECT
seq4() AS forIndex
FROM
TABLE(GENERATOR(ROWCOUNT => :FORALL))
)
);
LOOP
--** SSC-PRF-0003 - FETCH INSIDE A LOOP IS CONSIDERED A COMPLEX PATTERN, THIS COULD DEGRADE SNOWFLAKE PERFORMANCE. **
--** SSC-PRF-0001 - THIS STATEMENT HAS USAGES OF CURSOR FETCH BULK OPERATIONS **
cursorVariable := (
CALL FETCH_BULK_RECORD_COLLECTIONS_UDF(:cursorVariable, 2)
);
recordVariable := :cursorVariable:RESULT;
IF (ARRAY_SIZE(:recordVariable:column1) = 0) THEN
EXIT;
END IF;
FORALL := ARRAY_SIZE(:recordVariable:column1);
INSERT INTO table2(column1, column2)
(
SELECT
:recordVariable:column1[forIndex],
: recordVariable:column2[forIndex]
FROM
(
SELECT
seq4() AS forIndex
FROM
TABLE(GENERATOR(ROWCOUNT => :FORALL))
)
);
END LOOP;
cursorVariable := (
CALL CLOSE_BULK_CURSOR_UDF(:cursorVariable)
);
END;
$$;
COLUMN1| COLUMN2|
--------------------+-----------------------+
1.000000000000000000| 2.000000000000000000|
1.000000000000000000| 2.000000000000000000|
2.000000000000000000| 3.000000000000000000|
3.000000000000000000| 4.000000000000000000|
4.000000000000000000| 5.000000000000000000|
5.000000000000000000| 6.000000000000000000|
Nota
Essa transformação é feita somente quando nenhuma das transformações mencionadas anteriormente pode ser feita.
14. Multiple FORALL inside a LOOP clause¶
Nota
Esse padrão se aplica quando há mais de um FORALL no mesmo procedimento e ele atende à seguinte estrutura.
Oracle¶
CREATE OR REPLACE PROCEDURE myProcedure IS
CURSOR cursorVariable IS
SELECT * FROM table1;
TYPE collectionTypeDefinition IS TABLE OF table1%ROWTYPE;
collectionVariable collectionTypeDefinition;
BEGIN
OPEN cursorVariable;
LOOP
FETCH cursorVariable BULK COLLECT INTO collectionVariable limit 20;
EXIT WHEN collectionVariable.COUNT = 0;
FORALL forIndex IN collectionVariable.FIRST..collectionVariable.LAST
INSERT INTO table2 VALUES collectionVariable(forIndex);
FORALL forIndex IN collectionVariable.FIRST..collectionVariable.LAST
UPDATE table2 SET column1 = '54321' WHERE column2 = collectionVariable(forIndex).column2;
END LOOP;
CLOSE cursorVariable;
END;
COLUMN1| COLUMN2|
--------+--------+
54321| 2|
54321| 2|
54321| 3|
54321| 4|
54321| 5|
54321| 6|
Snowflake¶
CREATE OR REPLACE PROCEDURE myProcedure ()
RETURNS VARCHAR
LANGUAGE SQL
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"oracle"}}'
EXECUTE AS CALLER
AS
$$
BEGIN
--** SSC-PRF-0001 - THIS STATEMENT HAS USAGES OF CURSOR FETCH BULK OPERATIONS **
--** SSC-PRF-0003 - FETCH INSIDE A LOOP IS CONSIDERED A COMPLEX PATTERN, THIS COULD DEGRADE SNOWFLAKE PERFORMANCE. **
INSERT INTO table2
(
SELECT
* FROM
table1
);
--** SSC-PRF-0003 - FETCH INSIDE A LOOP IS CONSIDERED A COMPLEX PATTERN, THIS COULD DEGRADE SNOWFLAKE PERFORMANCE. **
UPDATE table2
SET column1 = '54321'
FROM
(
SELECT
* FROM
table1) AS collectionVariable
WHERE
column2 = collectionVariable.column2;
END;
$$;
COLUMN1| COLUMN2|
--------+--------+
54321| 2|
54321| 2|
54321| 3|
54321| 4|
54321| 5|
54321| 6|
15. Multiple FORALL inside different LOOP clauses¶
Nota
Esse padrão se aplica quando há mais de um FORALL no mesmo procedimento e ele atende à seguinte estrutura.
Oracle¶
CREATE OR REPLACE PROCEDURE myProcedure IS
CURSOR cursorVariable IS
SELECT * FROM table1;
CURSOR cursorVariable2 IS
SELECT * FROM table1;
TYPE collectionTypeDefinition IS
TABLE OF table1%ROWTYPE;
collectionVariable collectionTypeDefinition;
TYPE collectionTypeDefinition2 IS
TABLE OF table1%ROWTYPE;
collectionVariable2 collectionTypeDefinition2;
BEGIN
OPEN cursorVariable;
LOOP
FETCH cursorVariable BULK COLLECT INTO collectionVariable limit 2;
EXIT WHEN collectionVariable.COUNT = 0;
FORALL forIndex IN collectionVariable.FIRST..collectionVariable.LAST
INSERT INTO table2 VALUES collectionVariable(forIndex);
END LOOP;
CLOSE cursorVariable;
OPEN cursorVariable2;
LOOP
FETCH cursorVariable2 BULK COLLECT INTO collectionVariable2 limit 2;
EXIT WHEN collectionVariable2.COUNT = 0;
FORALL forIndex IN collectionVariable2.FIRST..collectionVariable2.LAST
UPDATE table2 SET column1 = '54321' WHERE column2 = collectionVariable2(forIndex).column2;
END LOOP;
CLOSE cursorVariable2;
END;
COLUMN1| COLUMN2|
--------+--------+
54321| 2|
54321| 2|
54321| 3|
54321| 4|
54321| 5|
54321| 6|
Snowflake¶
CREATE OR REPLACE PROCEDURE myProcedure ()
RETURNS VARCHAR
LANGUAGE SQL
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"oracle"}}'
EXECUTE AS CALLER
AS
$$
BEGIN
--** SSC-PRF-0001 - THIS STATEMENT HAS USAGES OF CURSOR FETCH BULK OPERATIONS **
--** SSC-PRF-0003 - FETCH INSIDE A LOOP IS CONSIDERED A COMPLEX PATTERN, THIS COULD DEGRADE SNOWFLAKE PERFORMANCE. **
INSERT INTO table2
(
SELECT
* FROM
table1
);
--** SSC-PRF-0001 - THIS STATEMENT HAS USAGES OF CURSOR FETCH BULK OPERATIONS **
--** SSC-PRF-0003 - FETCH INSIDE A LOOP IS CONSIDERED A COMPLEX PATTERN, THIS COULD DEGRADE SNOWFLAKE PERFORMANCE. **
UPDATE table2
SET column1 = '54321'
FROM
(
SELECT
* FROM
table1) AS collectionVariable2
WHERE
column2 = collectionVariable2.column2;
END;
$$;
COLUMN1| COLUMN2|
--------+--------+
54321| 2|
54321| 2|
54321| 3|
54321| 4|
54321| 5|
54321| 6|
16. FORALL with MERGE INTO with LOG ERRORS¶
Aviso
Esse padrão ainda não foi implementado
Oracle
CREATE OR REPLACE PROCEDURE procedure_example (
department_id_in IN source_table.DepartmentID%TYPE)
IS
TYPE employee_ids_t IS TABLE OF source_table%ROWTYPE
INDEX BY PLS_INTEGER;
employee_list employee_ids_t;
BEGIN
SELECT *
BULK COLLECT INTO employee_list
FROM source_table
WHERE DepartmentID = procedure_example.department_id_in;
FORALL indx IN 1 .. employee_list.COUNT
MERGE INTO target_table
USING (SELECT * FROM DUAL) src
ON (id = employee_list(indx).id)
WHEN MATCHED THEN
UPDATE SET
name = employee_list(indx).Name
WHEN NOT MATCHED THEN
INSERT (Id, Name, DepartmentID)
VALUES (employee_list(indx).Id, employee_list(indx).Name, employee_list(indx).DepartmentID)
LOG ERRORS INTO error_table('MERGE INTO ERROR')
REJECT LIMIT UNLIMITED;
END;
CALL procedure_example(10);
select * from target_table;
select * from error_table;
ID| NAME| DEPARTMENTID|
-----+--------+-------------+
101| Anurag| 10|
ORA_ERR_NUMBER$| ORA_ERR_MESG$ | ORA_ERR_ROWID$| ORA_ERR_OPTYP$ | ORA_ERR_TAG$ |
---------------+--------------------------------------------------------------------------------------+-------------------+----------------+--------------------+
12899| ORA-12899: value too large for column "TARGET_TABLE"."NAME" (actual: 15, maximum: 10)| AK6vdpADDAAABI7AAA| U |. MERGE INTO ERROR |
Snowflake¶
--Generated by SnowConvert---------------
CREATE OR REPLACE TRANSIENT TABLE target_staging_table(
Id INT PRIMARY KEY,
Name VARCHAR2(10) NOT NULL,
DepartmentID INT REFERENCES parent_table(Id)
)
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"oracle"}}'
;
--Generated by SnowConvert---------------
CREATE OR REPLACE PROCEDURE procedure_example (DEPARTMENT_ID_IN INT /*** MSC-WARNING - MSCEWI3129 - TYPE ATTRIBUTE 'employees.DepartmentID%TYPE' COULD NOT BE RESOLVED, SO IT WAS TRANSFORMED TO VARIANT ***/)
RETURNS VARCHAR
LANGUAGE SQL
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"oracle"}}'
EXECUTE AS CALLER
AS
$$
BEGIN
CREATE OR REPLACE TEMP TABLE SOURCE_TEMPORAL AS
WITH source_data as (
SELECT *
FROM source_table
WHERE DEPARTMENTID =: DEPARTMENT_ID_IN
)
SELECT source_data.*, parent_table.id as PARENT_KEY
FROM source_data
left join parent_table on source_data.DepartmentID = parent_table.id;
--All records violating foreign key integrity
INSERT INTO error_table (ERROR, COLUMN_NAME, REJECTED_RECORD)
SELECT
'Foreign Key Constraint Violated' ERROR,'KEY_COL' COLUMN_NAME, id
FROM SOURCE_TEMPORAL
WHERE PARENT_KEY IS NULL;
DELETE FROM SOURCE_TEMPORAL
WHERE PARENT_KEY IS NULL;
BEGIN
MERGE INTO target_table
USING SOURCE_TEMPORAL SRC
ON SRC.id = target_table.id
WHEN MATCHED THEN
UPDATE SET
name = SRC.name
WHEN NOT MATCHED THEN
INSERT (Id, Name, DepartmentID)
VALUES (SRC.Id, SRC.Name, SRC.DepartmentID);
EXCEPTION
WHEN OTHER THEN
CREATE OR REPLACE TEMPORARY STAGE my_int_stage
COPY_OPTIONS = (ON_ERROR='continue');
--Create my file and populate with data
COPY INTO @my_int_stage/my_file FROM (
SELECT * exclude(PARENT_KEY) FROM SOURCE_TEMPORAL
) OVERWRITE = TRUE ;
COPY INTO target_staging_table(id, name, DepartmentID)
FROM (
SELECT
-- distinct
t.$1, t.$2, t.$3
FROM @my_int_stage/my_file t
) ON_ERROR = CONTINUE;
INSERT INTO ERROR_TABLE (ERROR, FILE, LINE, CHARACTER, CATEGORY, CODE, SQL_STATE, COLUMN_NAME, ROW_NUMBER, REJECTED_RECORD)
SELECT
ERROR, FILE,LINE, CHARACTER, CATEGORY, CODE, SQL_STATE, COLUMN_NAME, ROW_NUMBER, REJECTED_RECORD
FROM TABLE(VALIDATE(target_staging_table, JOB_ID => '_last')) order by line; --The last charge on the current session
MERGE INTO target_table
USING target_staging_table staging
ON staging.id = target_table.id
WHEN MATCHED THEN
UPDATE SET
name = staging.name
WHEN NOT MATCHED THEN
INSERT (Id, Name, DepartmentID)
VALUES (staging.Id, staging.Name, staging.DepartmentID);
END;
return 'Awesome!';
END;
$$;
CALL procedure_example(10);
SELECT * FROM target_table;
SELECT * FROM error_table;
ERROR| FILE| LINE| CHARACTER| CATEGORY| CODE| SQL_STATE| COLUMN_NAME| ROW_NUMBER| REJECTED_RECORD| CREATE_TS|
---------------------------------------------------------------------+----------------------+-----+----------+------------+---------+----------+---------------------------------------------------+-----------------------+----------------------------+
User character length limit (10) exceeded by string 'Anurag111111111'| my_file_0_0_0.csv.gz| 1| 5| conversion| 100074| 54000| """TARGET_STAGING_TABLE""[""NAME"":2]"| 1| 101,Anurag111111111,10| 2023-08-03T14:33:40.978Z|
17. FORALL with INSERT with LOG ERRORS¶
Aviso
Esse padrão ainda não foi implementado
Oracle
CREATE OR REPLACE PROCEDURE procedure_example (
department_id_in IN source_table.DepartmentID%TYPE)
IS
TYPE employee_ids_t IS TABLE OF source_table%ROWTYPE
INDEX BY PLS_INTEGER;
employee_list employee_ids_t;
BEGIN
SELECT *
BULK COLLECT INTO employee_list
FROM source_table
WHERE DepartmentID = procedure_example.department_id_in;
FORALL indx IN 1 .. employee_list.COUNT
INSERT INTO target_table(Id, Name, DepartmentID)
VALUES (employee_list(indx).Id, employee_list(indx).Name, employee_list(indx).DepartmentID)
LOG ERRORS INTO error_table('MERGE INTO ERROR')
REJECT LIMIT UNLIMITED;
END;
ID| NAME| DEPARTMENTID|
-----+--------+-------------+
101| Anurag| 10|
ORA_ERR_NUMBER$| ORA_ERR_MESG$ | ORA_ERR_ROWID$| ORA_ERR_OPTYP$ | ORA_ERR_TAG$ |
---------------+--------------------------------------------------------------------------------------+-------------------+----------------+--------------------+
12899| ORA-12899: value too large for column "TARGET_TABLE"."NAME" (actual: 15, maximum: 10)| AK6vdpADDAAABI7AAA| U |. MERGE INTO ERROR |
Snowflake¶
--Generated by SnowConvert---------------
CREATE OR REPLACE TRANSIENT TABLE target_staging_table(
Id INT PRIMARY KEY,
Name VARCHAR2(10) NOT NULL,
DepartmentID INT REFERENCES parent_table(Id)
)
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"oracle"}}'
;
--Generated by SnowConvert---------------
CREATE OR REPLACE PROCEDURE procedure_example (DEPARTMENT_ID_IN INT /*** MSC-WARNING - MSCEWI3129 - TYPE ATTRIBUTE 'employees.DepartmentID%TYPE' COULD NOT BE RESOLVED, SO IT WAS TRANSFORMED TO VARIANT ***/)
RETURNS VARCHAR
LANGUAGE SQL
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"oracle"}}'
EXECUTE AS CALLER
AS
$$
BEGIN
CREATE OR REPLACE TEMP TABLE SOURCE_TEMPORAL AS
WITH source_data as (
SELECT *
FROM source_table
WHERE DEPARTMENTID =: DEPARTMENT_ID_IN
)
SELECT source_data.*, parent_table.id as PARENT_KEY
FROM source_data
left join parent_table on source_data.DepartmentID = parent_table.id;
--All records violating foreign key integrity
INSERT INTO error_table (ERROR, COLUMN_NAME, REJECTED_RECORD)
SELECT
'Foreign Key Constraint Violated' ERROR,'KEY_COL' COLUMN_NAME, id
FROM SOURCE_TEMPORAL
WHERE PARENT_KEY IS NULL;
DELETE FROM SOURCE_TEMPORAL
WHERE PARENT_KEY IS NULL;
BEGIN
INSERT INTO target_table (Id, Name, DepartmentID)
SELECT SRC.Id, SRC.Name, SRC.DepartmentID FROM SOURCE_TEMPORAL SRC;
EXCEPTION
WHEN OTHER THEN
CREATE OR REPLACE TEMPORARY STAGE my_int_stage
COPY_OPTIONS = (ON_ERROR='continue');
--Create my file and populate with data
COPY INTO @my_int_stage/my_file FROM (
SELECT * exclude(PARENT_KEY) FROM SOURCE_TEMPORAL
) OVERWRITE = TRUE ;
COPY INTO target_staging_table(id, name, DepartmentID)
FROM (
SELECT
-- distinct
t.$1, t.$2, t.$3
FROM @my_int_stage/my_file t
) ON_ERROR = CONTINUE;
INSERT INTO ERROR_TABLE (ERROR, FILE, LINE, CHARACTER, CATEGORY, CODE, SQL_STATE, COLUMN_NAME, ROW_NUMBER, REJECTED_RECORD)
SELECT
ERROR, FILE,LINE, CHARACTER, CATEGORY, CODE, SQL_STATE, COLUMN_NAME, ROW_NUMBER, REJECTED_RECORD
FROM TABLE(VALIDATE(target_staging_table, JOB_ID => '_last')) order by line; --The last charge on the current session
INSERT INTO target_table (Id, Name, DepartmentID)
SELECT staging.Id, staging.Name, staging.DepartmentID FROM target_staging_table staging;
END;
END;
$$;
CALL procedure_example(10);
SELECT * FROM target_table;
SELECT * FROM error_table;
ERROR| FILE| LINE| CHARACTER| CATEGORY| CODE| SQL_STATE| COLUMN_NAME| ROW_NUMBER| REJECTED_RECORD| CREATE_TS|
---------------------------------------------------------------------+----------------------+-----+----------+------------+---------+----------+---------------------------------------------------+-----------------------+----------------------------+
User character length limit (10) exceeded by string 'Anurag111111111'| my_file_0_0_0.csv.gz| 1| 5| conversion| 100074| 54000| """TARGET_STAGING_TABLE""[""NAME"":2]"| 1| 101,Anurag111111111,10| 2023-08-03T14:33:40.978Z|
Problemas conhecidos¶
Não foram encontrados problemas.
EWIs relacionados¶
SSC-EWI-0030: A instrução abaixo tem usos de SQL dinâmico.
SSC-EWI-0036: Tipo de dados convertido em outro tipo de dados.
SSC-EWI-0056: Create Type não tem suporte.
SSC-EWI-0058: No momento, a funcionalidade não é compatível com o Snowflake Scripting.
SSC-EWI-0062: O uso do tipo personalizado foi alterado para variante.
SSC-EWI-OR0049: Ainda não há suporte para constantes de pacote no pacote stateful.
SSC-FDM-0006: A coluna de tipo de número pode não se comportar de forma semelhante no Snowflake.
SSC-FDM-0015: o tipo personalizado referenciado na consulta não foi encontrado.
SSC-PRF-0001: Essa instrução tem usos de operações em massa de busca de cursor.
SSC-PRF-0003: A busca dentro de um loop é considerada um padrão complexo, o que pode prejudicar o desempenho do Snowflake.
IF¶
Descrição¶
A instrução IF
executa ou ignora uma sequência de uma ou mais instruções, dependendo do valor de uma expressão BOOLEAN
. Para obter mais informações sobre Oracle IF, veja aqui.
IF boolean_expression THEN
statement
[ statement ]...
[
ELSIF boolean_expression THEN
statement
[ statement ]... ]...
[
ELSE
statement [ statement ]... ] END IF ;
IF ( <condition> ) THEN
<statement>;
[ <statement>; ... ]
[
ELSEIF ( <condition> ) THEN
<statement>;
[ <statement>; ... ]
]
[
ELSE
<statement>;
[ <statement>; ... ]
]
END IF;
Amostra de padrões da origem¶
Exemplo de tabela auxiliar¶
CREATE TABLE if_table(col1 varchar(30));
CREATE OR REPLACE TABLE PUBLIC.if_table (col1 varchar(30));
Possíveis variações de IF¶
Oracle¶
CREATE OR REPLACE PROCEDURE ifExample1 ( flag NUMBER )
IS
BEGIN
IF flag = 1 THEN
INSERT INTO if_table(col1) VALUES ('one');
END IF;
END;
CALL ifExample1(1);
SELECT * FROM if_table;
CREATE OR REPLACE PROCEDURE ifExample2 ( flag NUMBER )
IS
BEGIN
IF flag = 1 THEN
INSERT INTO if_table(col1) VALUES ('one');
ELSE
INSERT INTO if_table(col1) VALUES ('Unexpected input.');
END IF;
END;
CALL ifExample2(2);
SELECT * FROM if_table;
CREATE OR REPLACE PROCEDURE ifExample3 ( flag NUMBER )
IS
BEGIN
IF flag = 1 THEN
INSERT INTO if_table(col1) VALUES ('one');
ELSIF flag = 2 THEN
INSERT INTO if_table(col1) VALUES ('two');
ELSIF flag = 3 THEN
INSERT INTO if_table(col1) VALUES ('three');
END IF;
END;
CALL ifExample3(3);
SELECT * FROM if_table;
CREATE OR REPLACE PROCEDURE ifExample4 ( flag NUMBER )
IS
BEGIN
IF flag = 1 THEN
INSERT INTO if_table(col1) VALUES ('one');
ELSIF flag = 2 THEN
INSERT INTO if_table(col1) VALUES ('two');
ELSIF flag = 3 THEN
INSERT INTO if_table(col1) VALUES ('three');
ELSE
INSERT INTO if_table(col1) VALUES ('Unexpected input.');
END IF;
END;
CALL ifExample4(4);
SELECT * FROM if_table;
|COL1|
|----|
|one |
|COL1 |
|-----------------|
|Unexpected input.|
|COL1 |
|-----|
|three|
|COL1 |
|-----------------|
|Unexpected input.|
Script Snowflake¶
CREATE OR REPLACE PROCEDURE ifExample1 (flag NUMBER(38, 18))
RETURNS VARCHAR
LANGUAGE SQL
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"oracle"}}'
EXECUTE AS CALLER
AS
$$
BEGIN
IF (:flag = 1) THEN
INSERT INTO if_table(col1) VALUES ('one');
END IF;
END;
$$;
CALL ifExample1(1);
SELECT * FROM
if_table;
CREATE OR REPLACE PROCEDURE ifExample2 (flag NUMBER(38, 18))
RETURNS VARCHAR
LANGUAGE SQL
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"oracle"}}'
EXECUTE AS CALLER
AS
$$
BEGIN
IF (:flag = 1) THEN
INSERT INTO if_table(col1) VALUES ('one');
ELSE
INSERT INTO if_table(col1) VALUES ('Unexpected input.');
END IF;
END;
$$;
CALL ifExample2(2);
SELECT * FROM
if_table;
CREATE OR REPLACE PROCEDURE ifExample3 (flag NUMBER(38, 18))
RETURNS VARCHAR
LANGUAGE SQL
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"oracle"}}'
EXECUTE AS CALLER
AS
$$
BEGIN
IF (:flag = 1) THEN
INSERT INTO if_table(col1) VALUES ('one');
ELSEIF (:flag = 2) THEN
INSERT INTO if_table(col1) VALUES ('two');
ELSEIF (:flag = 3) THEN
INSERT INTO if_table(col1) VALUES ('three');
END IF;
END;
$$;
CALL ifExample3(3);
SELECT * FROM
if_table;
CREATE OR REPLACE PROCEDURE ifExample4 (flag NUMBER(38, 18))
RETURNS VARCHAR
LANGUAGE SQL
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},"attributes":{"component":"oracle"}}'
EXECUTE AS CALLER
AS
$$
BEGIN
IF (:flag = 1) THEN
INSERT INTO if_table(col1) VALUES ('one');
ELSEIF (:flag = 2) THEN
INSERT INTO if_table(col1) VALUES ('two');
ELSEIF (:flag = 3) THEN
INSERT INTO if_table(col1) VALUES ('three');
ELSE
INSERT INTO if_table(col1) VALUES ('Unexpected input.');
END IF;
END;
$$;
CALL ifExample4(4);
SELECT * FROM if_table;
|COL1|
|----|
|one |
|COL1 |
|-----------------|
|Unexpected input.|
|COL1 |
|-----|
|three|
|COL1 |
|-----------------|
|Unexpected input.|
Problemas conhecidos¶
Não foram encontrados problemas.
EWIS relacionados¶
Sem EWIs relacionados.
IS EMPTY¶
Aviso
Esta seção é um trabalho em andamento; as informações podem mudar no futuro.
Descrição¶
Use as condições IS [NOT] EMPTY para testar se uma tabela aninhada especificada está vazia, independentemente de qualquer elemento da coleção ser NULL. (Documentação).
Sintaxe do Oracle¶
nested_table IS [ NOT ] EMPTY
Amostra de padrões da origem¶
Oracle¶
O exemplo a seguir mostra o uso da instrução IS EMPTY. A instrução é aplicada sobre uma tabela aninhada que usa um UDT como tipo de definição. A saída mostra o nome dos funcionários que não têm um número de telefone.
CREATE TYPE phone_number_type AS OBJECT (phone_number VARCHAR2(30));
/
CREATE TYPE phone_number_list AS TABLE OF phone_number_type;
CREATE TABLE employee (
emp_id NUMBER,
emp_name VARCHAR2(50),
phone_numbers_col phone_number_list
) NESTED TABLE phone_numbers_col STORE AS nested_tab return as value;
INSERT INTO employee VALUES (
1,
'John Doe',
phone_number_list(phone_number_type('1234567890'))
);
/
INSERT INTO employee VALUES (
2,
'Jane Smith',
phone_number_list()
);
SELECT emp_name
FROM employee
WHERE phone_numbers_col IS EMPTY;
EMP_NAME |
---|
Jane Smith |
Snowflake¶
A consulta do Snowflake mostrada abaixo é a equivalência da funcionalidade da instrução IS EMPTY. Em particular, a instrução IS EMPTY apresenta uma diferença entre um objeto NULL e um objeto EMPTY.
Observe que User-Defined Types são transformados em um VARIANT. O tipo VARIANT no Snowflake é capaz de armazenar objetos e matrizes. Como uma tabela aninhada é uma sequência de informações, o tipo ARRAY é o tipo mais adequado para redefini-las e verificar se o objeto ARRAY está vazio.
A solução equivalente ARRAY_SIZE também permite solicitar a nulidade da tabela aninhada (transformada em VARIANT). Em outras palavras, o tipo VARIANT também pode armazenar NULLs e ARRAYs vazio.
!!!RESOLVE EWI!!! /*** SSC-EWI-0056 - CUSTOM TYPES ARE NOT SUPPORTED IN SNOWFLAKE BUT REFERENCES TO THIS CUSTOM TYPE WERE CHANGED TO VARIANT ***/!!!
CREATE TYPE phone_number_type AS OBJECT (phone_number VARCHAR2(30))
;
!!!RESOLVE EWI!!! /*** SSC-EWI-0073 - PENDING FUNCTIONAL EQUIVALENCE REVIEW FOR 'NESTED TABLE' NODE ***/!!!
CREATE TYPE phone_number_list AS TABLE OF phone_number_type;
CREATE OR REPLACE TABLE employee (
emp_id NUMBER(38, 18) /*** SSC-FDM-0006 - NUMBER TYPE COLUMN MAY NOT BEHAVE SIMILARLY IN SNOWFLAKE. ***/,
emp_name VARCHAR(50),
phone_numbers_col VARIANT !!!RESOLVE EWI!!! /*** SSC-EWI-0062 - CUSTOM TYPE 'phone_number_list' USAGE CHANGED TO VARIANT ***/!!!
)
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"oracle"}}'
;
CREATE OR REPLACE VIEW PUBLIC.employee_view
COMMENT = '{ "origin": "sf_sc", "name": "snowconvert", "version": { "major": 0, "minor": 0, "patch": "0" }, "attributes": { "component": "oracle", "convertedOn": "" }}'
AS
SELECT
emp_id,
emp_name,
phone_numbers_col
FROM
employee;
INSERT INTO employee
VALUES (
1,
'John Doe',
phone_number_list(phone_number_type('1234567890') !!!RESOLVE EWI!!! /*** SSC-EWI-0073 - PENDING FUNCTIONAL EQUIVALENCE REVIEW FOR 'phone_number_type' NODE ***/!!!) !!!RESOLVE EWI!!! /*** SSC-EWI-0073 - PENDING FUNCTIONAL EQUIVALENCE REVIEW FOR 'phone_number_list' NODE ***/!!!
);
INSERT INTO employee
VALUES (
2,
'Jane Smith',
phone_number_list() !!!RESOLVE EWI!!! /*** SSC-EWI-0073 - PENDING FUNCTIONAL EQUIVALENCE REVIEW FOR 'phone_number_list' NODE ***/!!!
);
SELECT emp_name
FROM
employee
WHERE
ARRAY_SIZE( phone_numbers_col) = 0;
EMP_NAME |
---|
Jane Smith |
Outras combinações possíveis¶
Description | Oracle | Snowflake |
---|---|---|
Ask for a IS NOT EMPTY |
|
|
Ask for NULL instead of EMPTY |
|
|
Problemas conhecidos¶
1. User-defined types are being transformed into Variant.¶
Os tipos definidos pelo usuário não são compatíveis, portanto, são transformados em tipos Variant, o que pode exigir esforço manual para garantir algumas funcionalidades.
Consulte a página a seguir para obter mais informações:
2. Nested tables are not supported.¶
No momento, não há suporte para tabelas aninhadas. A melhor abordagem com base nessa equivalência é tratar as tabelas aninhadas como Variant, mas declarar Arrays com dados JSON dentro e executar a função PARSE_JSON do Snowflake para preencher as informações aninhadas.
Leia as páginas a seguir para obter mais informações:
3. Insert statements are not supported for User-defined types.¶
Como os tipos definidos pelo usuário não são suportados, consequentemente, os comandos Insert para esses tipos não são suportados. Especificamente em tabelas aninhadas, a instrução INSERT INTO ... VALUES
deve ser alterada para INSERT INTO ...SELECT
porque se espera que a função ARRAY_CONSTRUCT seja usada nesse padrão.
Consulte a página a seguir para obter mais informações:
4. Logic should be adapted to ARRAY
types.¶
Como as tabelas aninhadas devem ser transformadas de forma equivalente para VARIANT
e se comportar como ARRAYs,
, a funcionalidade e a lógica dos procedimentos de implementação e a interação com os dados devem ser adaptadas.
Analise os exemplos a seguir:
4.1 Equivalência de procedimentos¶
create or replace procedure proc1
as
col1 phone_number_list:= phone_number_list();
begin
IF col1 IS EMPTY
THEN
dbms_output.put_line('IS EMPTY');
END IF;
end;
CREATE OR REPLACE PROCEDURE proc1 ()
RETURNS VARCHAR
LANGUAGE SQL
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"oracle"}}'
EXECUTE AS CALLER
AS
$$
DECLARE
col1 VARIANT /*** SSC-FDM-0015 - REFERENCED CUSTOM TYPE 'phone_number_list' IN QUERY NOT FOUND, USAGES MAY BE AFFECTED ***/ := phone_number_list() !!!RESOLVE EWI!!! /*** SSC-EWI-0073 - PENDING FUNCTIONAL EQUIVALENCE REVIEW FOR 'phone_number_list' NODE ***/!!!;
BEGIN
IF (ARRAY_SIZE(:col1) = 0) THEN
--** SSC-FDM-OR0035 - CHECK UDF IMPLEMENTATION FOR DBMS_OUTPUT.PUT_LINE_UDF. **
CALL DBMS_OUTPUT.PUT_LINE_UDF('IS EMPTY');
END IF;
END;
$$;
PROC1 |
---|
IS EMPTY |
4.2 Instruções Select¶
As saídas podem diferir de tabelas para ARRAYs
.
Oracle¶
SELECT
t.*
FROM
employee e,
table(e.phone_numbers_col) t
WHERE
emp_id = 1;
PHONE_NUMBER |
---|
1234567890 |
Snowflake¶
SELECT
t.*
FROM
employee e,
!!!RESOLVE EWI!!! /*** SSC-EWI-OR0035 - TABLE FUNCTION IS NOT SUPPORTED WHEN IT IS USED AS A COLLECTION OF EXPRESSIONS ***/!!!
table(e.phone_numbers_col) t
WHERE
emp_id = 1;
PHONE_NUMBERS_COL |
---|
[ 1234567890 ] |
EWIs relacionados¶
SSC-EWI-0056: Create Type não tem suporte.
SSC-EWI-0062: O uso do tipo personalizado foi alterado para variante.
SSC-EWI-0073: Revisão de equivalência funcional pendente.
SSC-EWI-OR0035: Não há suporte para a função de tabela quando ela é usada como uma coleção de expressões.
SSC-FDM-0006: A coluna de tipo de número pode não se comportar de forma semelhante no Snowflake.
SSC-FDM-0015: o tipo personalizado referenciado na consulta não foi encontrado.
SSC-FDM-OR0035: DBMS_OUTPUT.PUTLINE verifique a implementação de UDF.
LOCK TABLE¶
Nota
Instrução não relevante.
Aviso
Observe que essa instrução é removida da migração porque é uma sintaxe não relevante. Isso significa que não é necessária no Snowflake.
Descrição¶
No Oracle, a instrução LOCK TABLE
permite adquirir explicitamente um bloqueio de tabela compartilhado ou exclusivo na tabela especificada. O bloqueio da tabela dura até o final da transação atual. Veja mais informações aqui.
Sintaxe
LOCK TABLE tableName IN { SHARE | EXCLUSIVE } MODE
Amostra de padrões da origem¶
Tabela de bloqueio¶
Observe que, neste exemplo, a instrução LOCK TABLE
foi excluída. Isso ocorre porque o Snowflake lida com o bloqueio em um método diferente por meio de transações.
LOCK TABLE table1 IN EXCLUSIVE MODE;
[Empty output]
LOG ERROR¶
Nota
Algumas partes do código de saída foram omitidas por motivos de clareza.
Descrição¶
A instrução FORALL
executa uma instrução DML várias vezes, com valores diferentes nas cláusulas VALUES
e WHERE
. (Instrução FORALL da referência de linguagem Oracle PL/SQL).
FORALL index IN bounds_clause [ SAVE ] [ EXCEPTIONS ] dml_statement ;
Aviso
O Snowflake Scripting não tem equivalência direta com a instrução FORALL
, mas pode ser emulado com diferentes soluções alternativas para obter equivalência funcional.
Amostra de padrões da origem¶
Dados de configuração¶
Oracle¶
CREATE TABLE error_table (
ORA_ERR_NUMBER$ NUMBER,
ORA_ERR_MESG$ VARCHAR2(2000),
ORA_ERR_ROWID$ ROWID,
ORA_ERR_OPTYP$ VARCHAR2(2),
ORA_ERR_TAG$ VARCHAR2(2000)
);
--departments
CREATE TABLE parent_table(
Id INT PRIMARY KEY,
Name VARCHAR2(10)
);
INSERT INTO parent_table VALUES (10, 'IT');
INSERT INTO parent_table VALUES (20, 'HR');
INSERT INTO parent_table VALUES (30, 'INFRA');
--employees
CREATE TABLE source_table(
Id INT PRIMARY KEY,
Name VARCHAR2(20) NOT NULL,
DepartmentID INT REFERENCES parent_table(Id)
);
INSERT INTO source_table VALUES (101, 'Anurag111111111', 10);
INSERT INTO source_table VALUES (102, 'Pranaya11111111', 20);
INSERT INTO source_table VALUES (103, 'Hina11111111111', 30);
--a copy of source
CREATE TABLE target_table(
Id INT PRIMARY KEY,
Name VARCHAR2(10) NOT NULL,
DepartmentID INT REFERENCES parent_table(Id)
);
INSERT INTO target_table VALUES (101, 'Anurag', 10);
Snowflake¶
CREATE OR REPLACE TABLE error_table (
"ORA_ERR_NUMBER$" NUMBER(38, 18) /*** SSC-FDM-0006 - NUMBER TYPE COLUMN MAY NOT BEHAVE SIMILARLY IN SNOWFLAKE. ***/,
"ORA_ERR_MESG$" VARCHAR(2000),
"ORA_ERR_ROWID$" VARCHAR(18) !!!RESOLVE EWI!!! /*** SSC-EWI-0036 - ROWID DATA TYPE CONVERTED TO VARCHAR ***/!!!,
"ORA_ERR_OPTYP$" VARCHAR(2),
"ORA_ERR_TAG$" VARCHAR(2000)
)
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"oracle"}}'
;
--departments
CREATE OR REPLACE TABLE parent_table (
Id INT PRIMARY KEY,
Name VARCHAR(10)
)
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"oracle"}}'
;
INSERT INTO parent_table
VALUES (10, 'IT');
INSERT INTO parent_table
VALUES (20, 'HR');
INSERT INTO parent_table
VALUES (30, 'INFRA');
--employees
CREATE OR REPLACE TABLE source_table (
Id INT PRIMARY KEY,
Name VARCHAR(20) NOT NULL,
DepartmentID INT REFERENCES parent_table (Id)
)
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"oracle"}}'
;
INSERT INTO source_table
VALUES (101, 'Anurag111111111', 10);
INSERT INTO source_table
VALUES (102, 'Pranaya11111111', 20);
INSERT INTO source_table
VALUES (103, 'Hina11111111111', 30);
--a copy of source
CREATE OR REPLACE TABLE target_table (
Id INT PRIMARY KEY,
Name VARCHAR(10) NOT NULL,
DepartmentID INT REFERENCES parent_table (Id)
)
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"oracle"}}'
;
INSERT INTO target_table
VALUES (101, 'Anurag', 10);
1. MERGE INTO Inside a FORALL¶
Oracle
Os três casos abaixo têm a mesma transformação para o Snowflake Scripting e são funcionalmente equivalentes.
CREATE OR REPLACE PROCEDURE procedure_example (
department_id_in IN source_table.DepartmentID%TYPE)
IS
TYPE employee_ids_t IS TABLE OF source_table%ROWTYPE
INDEX BY PLS_INTEGER;
employee_list employee_ids_t;
BEGIN
SELECT *
BULK COLLECT INTO employee_list
FROM source_table
WHERE DepartmentID = procedure_example.department_id_in;
FORALL indx IN 1 .. employee_list.COUNT
MERGE INTO target_table
USING (SELECT * FROM DUAL) src
ON (id = employee_list(indx).id)
WHEN MATCHED THEN
UPDATE SET
name = employee_list(indx).Name
WHEN NOT MATCHED THEN
INSERT (Id, Name, DepartmentID)
VALUES (employee_list(indx).Id, employee_list(indx).Name, employee_list(indx).DepartmentID)
LOG ERRORS INTO error_table('MERGE INTO ERROR')
REJECT LIMIT UNLIMITED;
END;
CALL procedure_example(10);
select * from target_table;
select * from error_table;
ID| NAME| DEPARTMENTID|
-----+--------+-------------+
101| Anurag| 10|
ORA_ERR_NUMBER$| ORA_ERR_MESG$ | ORA_ERR_ROWID$| ORA_ERR_OPTYP$ | ORA_ERR_TAG$ |
---------------+--------------------------------------------------------------------------------------+-------------------+----------------+--------------------+
12899| ORA-12899: value too large for column "TARGET_TABLE"."NAME" (actual: 15, maximum: 10)| AK6vdpADDAAABI7AAA| U |. MERGE INTO ERROR |
Snowflake
CREATE OR REPLACE PROCEDURE procedure_example (department_id_in VARIANT !!!RESOLVE EWI!!! /*** SSC-EWI-OR0129 - TYPE ATTRIBUTE 'source_table.DepartmentID%TYPE' COULD NOT BE RESOLVED, SO IT WAS TRANSFORMED TO VARIANT ***/!!!)
RETURNS VARCHAR
LANGUAGE SQL
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},"attributes":{"component":"oracle"}}'
EXECUTE AS CALLER
AS
$$
DECLARE
-- !!!RESOLVE EWI!!! /*** SSC-EWI-0058 - FUNCTIONALITY FOR 'PL COLLECTION TYPE DEFINITION' IS NOT CURRENTLY SUPPORTED BY SNOWFLAKE SCRIPTING ***/!!!
-- TYPE employee_ids_t IS TABLE OF source_table%ROWTYPE
-- INDEX BY PLS_INTEGER;
employee_list VARIANT !!!RESOLVE EWI!!! /*** SSC-EWI-0062 - CUSTOM TYPE 'employee_ids_t' USAGE CHANGED TO VARIANT ***/!!!;
FORALL INTEGER;
BEGIN
!!!RESOLVE EWI!!! /*** SSC-EWI-0058 - FUNCTIONALITY FOR 'RECORDS AND COLLECTIONS' IS NOT CURRENTLY SUPPORTED BY SNOWFLAKE SCRIPTING ***/!!!
SELECT *
BULK COLLECT INTO employee_list
FROM source_table
WHERE DepartmentID = procedure_example.department_id_in;
FORALL := ARRAY_SIZE(:employee_list);
MERGE INTO target_table
USING (SELECT * FROM
(
SELECT
seq4() AS indx
FROM
TABLE(GENERATOR(ROWCOUNT => :FORALL))
)) src
ON (id = : employee_list[indx]:id)
WHEN MATCHED THEN
UPDATE SET
name = : employee_list[indx]:Name
WHEN NOT MATCHED THEN
INSERT (Id, Name, DepartmentID)
VALUES (:employee_list[indx]:Id, : employee_list[indx]:Name, : employee_list[indx]:DepartmentID)
-- --** SSC-FDM-OR0031 - THE ERROR LOGGING CLAUSE IN DML STATEMENTS IS NOT SUPPORTED BY SNOWFLAKE **
-- LOG ERRORS INTO error_table('MERGE INTO ERROR')
-- REJECT LIMIT UNLIMITED
;
END;
$$;
CALL procedure_example(10);
select * from
target_table;
select * from
error_table;
COLUMN1| COLUMN2|
--------------------+-----------------------+
1.000000000000000000| 2.000000000000000000|
1.000000000000000000| 2.000000000000000000|
2.000000000000000000| 3.000000000000000000|
3.000000000000000000| 4.000000000000000000|
4.000000000000000000| 5.000000000000000000|
5.000000000000000000| 6.000000000000000000|
Nota
Os EWIs MSCCP0005 e SSC-PRF-0003 são adicionados em cada ocorrência de FETCH BULK COLLECT na instrução FORALL.
2. FORALL With INSERT INTO¶
Oracle¶
CREATE OR REPLACE PROCEDURE myProcedure IS
CURSOR cursorVariable IS
SELECT * FROM table1;
TYPE collectionTypeDefinition IS TABLE OF table1%ROWTYPE;
collectionVariable collectionTypeDefinition;
BEGIN
OPEN cursorVariable;
LOOP
FETCH cursorVariable BULK COLLECT INTO collectionVariable limit 2;
EXIT WHEN collectionVariable.COUNT = 0;
FORALL forIndex IN collectionVariable.FIRST..collectionVariable.LAST
INSERT INTO table2 VALUES collectionVariable(forIndex);
collectionVariable.DELETE;
END LOOP;
CLOSE cursorVariable;
END;
COLUMN1| COLUMN2|
--------+--------+
1| 2|
1| 2|
2| 3|
3| 4|
4| 5|
5| 6|
Snowflake¶
CREATE OR REPLACE PROCEDURE myProcedure ()
RETURNS VARCHAR
LANGUAGE SQL
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"oracle"}}'
EXECUTE AS CALLER
AS
$$
BEGIN
--** SSC-PRF-0001 - THIS STATEMENT HAS USAGES OF CURSOR FETCH BULK OPERATIONS **
--** SSC-PRF-0003 - FETCH INSIDE A LOOP IS CONSIDERED A COMPLEX PATTERN, THIS COULD DEGRADE SNOWFLAKE PERFORMANCE. **
INSERT INTO table2
(
SELECT
* FROM
table1
);
END;
$$;
COLUMN1| COLUMN2|
--------------------+-----------------------+
1.000000000000000000| 2.000000000000000000|
1.000000000000000000| 2.000000000000000000|
2.000000000000000000| 3.000000000000000000|
3.000000000000000000| 4.000000000000000000|
4.000000000000000000| 5.000000000000000000|
5.000000000000000000| 6.000000000000000000|
3. FORALL With Multiple Fetched Collections¶
Oracle¶
CREATE OR REPLACE PROCEDURE myProcedure IS
CURSOR cursorVariable IS
SELECT * FROM table1;
column1Collection dbms_sql.NUMBER_table;
column2Collection dbms_sql.NUMBER_table;
BEGIN
OPEN cursorVariable;
LOOP
FETCH cursorVariable BULK COLLECT INTO column1Collection, column2Collection limit 20;
EXIT WHEN column1Collection.COUNT = 0;
FORALL forIndex IN 1..column1Collection.COUNT
INSERT INTO table2 VALUES (
column1Collection(forIndex),
column2Collection(forIndex)
);
END LOOP;
CLOSE cursorVariable;
END;
CREATE OR REPLACE PROCEDURE myProcedure IS
CURSOR cursorVariable IS
SELECT * FROM table1;
column1Collection dbms_sql.NUMBER_table;
column2Collection dbms_sql.NUMBER_table;
BEGIN
OPEN cursorVariable;
LOOP
FETCH cursorVariable BULK COLLECT INTO column1Collection, column2Collection limit 2;
EXIT WHEN column1Collection.COUNT = 0;
FORALL forIndex IN 1..column1Collection.COUNT
UPDATE table2 SET column2 = column2Collection(forIndex)
WHERE column1 = column1Collection(forIndex);
END LOOP;
CLOSE cursorVariable;
END;
COLUMN1| COLUMN2|
--------+--------+
1| 2|
2| 3|
3| 4|
4| 5|
5| 6|
1| 2|
COLUMN1| COLUMN2|
--------+--------+
1| 2|
Snowflake¶
CREATE OR REPLACE PROCEDURE myProcedure ()
RETURNS VARCHAR
LANGUAGE SQL
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"oracle"}}'
EXECUTE AS CALLER
AS
$$
BEGIN
--** SSC-PRF-0001 - THIS STATEMENT HAS USAGES OF CURSOR FETCH BULK OPERATIONS **
--** SSC-PRF-0003 - FETCH INSIDE A LOOP IS CONSIDERED A COMPLEX PATTERN, THIS COULD DEGRADE SNOWFLAKE PERFORMANCE. **
INSERT INTO table2
(
SELECT
$1,
$2
FROM
table1
);
END;
$$;
CREATE OR REPLACE PROCEDURE myProcedure ()
RETURNS VARCHAR
LANGUAGE SQL
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"oracle"}}'
EXECUTE AS CALLER
AS
$$
BEGIN
--** SSC-PRF-0001 - THIS STATEMENT HAS USAGES OF CURSOR FETCH BULK OPERATIONS **
--** SSC-PRF-0003 - FETCH INSIDE A LOOP IS CONSIDERED A COMPLEX PATTERN, THIS COULD DEGRADE SNOWFLAKE PERFORMANCE. **
UPDATE table2
SET column2 = column1Collection.$2
FROM
(
SELECT
* FROM
table1) AS column1Collection
WHERE
column1 = column1Collection.$1;
END;
$$;
COLUMN1| COLUMN2|
--------------------+-----------------------+
1.000000000000000000| 2.000000000000000000|
1.000000000000000000| 2.000000000000000000|
2.000000000000000000| 3.000000000000000000|
3.000000000000000000| 4.000000000000000000|
4.000000000000000000| 5.000000000000000000|
5.000000000000000000| 6.000000000000000000|
COLUMN1| COLUMN2|
--------------------+-----------------------+
1.000000000000000000| 2.000000000000000000|
4. FORALL With Record of Collections¶
Oracle¶
CREATE OR REPLACE PROCEDURE myProcedure IS
CURSOR cursorVariable IS
SELECT * FROM table1;
TYPE recordType IS RECORD(
column1Collection dbms_sql.NUMBER_table,
column2Collection dbms_sql.NUMBER_table
);
columnRecord recordType;
BEGIN
OPEN cursorVariable;
LOOP
FETCH cursorVariable BULK COLLECT INTO columnRecord.column1Collection, columnRecord.column2Collection limit 20;
FORALL forIndex IN 1..columnRecord.column1Collection.COUNT
INSERT INTO table2 VALUES (
columnRecord.column1Collection(forIndex),
columnRecord.column2Collection(forIndex)
);
EXIT WHEN cursorVariable%NOTFOUND;
END LOOP;
CLOSE cursorVariable;
END;
COLUMN1| COLUMN2|
--------+--------+
1| 2|
1| 2|
2| 3|
3| 4|
4| 5|
5| 6|
Snowflake¶
CREATE OR REPLACE PROCEDURE myProcedure ()
RETURNS VARCHAR
LANGUAGE SQL
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"oracle"}}'
EXECUTE AS CALLER
AS
$$
BEGIN
--** SSC-PRF-0001 - THIS STATEMENT HAS USAGES OF CURSOR FETCH BULK OPERATIONS **
--** SSC-PRF-0003 - FETCH INSIDE A LOOP IS CONSIDERED A COMPLEX PATTERN, THIS COULD DEGRADE SNOWFLAKE PERFORMANCE. **
INSERT INTO table2
(
SELECT
$1,
$2
FROM
table1
);
END;
$$;
COLUMN1| COLUMN2|
--------------------+-----------------------+
1.000000000000000000| 2.000000000000000000|
1.000000000000000000| 2.000000000000000000|
2.000000000000000000| 3.000000000000000000|
3.000000000000000000| 4.000000000000000000|
4.000000000000000000| 5.000000000000000000|
5.000000000000000000| 6.000000000000000000|
5. FORALL With Dynamic SQL¶
Oracle¶
CREATE OR REPLACE PROCEDURE myProcedure IS
cursorVariable SYS_REFCURSOR;
TYPE collectionTypeDefinition IS
TABLE OF table1%ROWTYPE;
collectionVariable collectionTypeDefinition;
query VARCHAR(200) := 'SELECT * FROM table1';
BEGIN
OPEN cursorVariable FOR query;
LOOP
FETCH cursorVariable BULK COLLECT INTO collectionVariable;
EXIT WHEN collectionVariable.COUNT = 0;
FORALL forIndex IN collectionVariable.FIRST..collectionVariable.LAST
INSERT INTO table2 VALUES collectionVariable(forIndex);
collectionVariable.DELETE;
END LOOP;
CLOSE cursorVariable;
END;
COLUMN1| COLUMN2|
--------+--------+
1| 2|
1| 2|
2| 3|
3| 4|
4| 5|
5| 6|
Snowflake¶
CREATE OR REPLACE PROCEDURE myProcedure ()
RETURNS VARCHAR
LANGUAGE SQL
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"oracle"}}'
EXECUTE AS CALLER
AS
$$
DECLARE
query VARCHAR(200) := 'SELECT * FROM
table1';
BEGIN
--** SSC-PRF-0001 - THIS STATEMENT HAS USAGES OF CURSOR FETCH BULK OPERATIONS **
--** SSC-PRF-0003 - FETCH INSIDE A LOOP IS CONSIDERED A COMPLEX PATTERN, THIS COULD DEGRADE SNOWFLAKE PERFORMANCE. **
!!!RESOLVE EWI!!! /*** SSC-EWI-0030 - THE STATEMENT BELOW HAS USAGES OF DYNAMIC SQL. ***/!!!
EXECUTE IMMEDIATE 'CREATE OR REPLACE TEMPORARY TABLE query AS ' || :query;
INSERT INTO table2
(
SELECT
*
FROM
query
);
END;
$$;
COLUMN1| COLUMN2|
--------------------+-----------------------+
1.000000000000000000| 2.000000000000000000|
1.000000000000000000| 2.000000000000000000|
2.000000000000000000| 3.000000000000000000|
3.000000000000000000| 4.000000000000000000|
4.000000000000000000| 5.000000000000000000|
5.000000000000000000| 6.000
6. FORALL Without LOOPS¶
Oracle¶
CREATE OR REPLACE PROCEDURE myProcedure IS
TYPE collectionTypeDefinition IS TABLE OF table1%ROWTYPE;
collectionVariable collectionTypeDefinition;
BEGIN
SELECT * BULK COLLECT INTO collectionVariable FROM table1;
FORALL forIndex IN 1..collectionVariable.COUNT
INSERT INTO table2 VALUES (
collectionVariable (forIndex).column1,
collectionVariable (forIndex).column2
);
collectionVariable.DELETE;
END;
COLUMN1| COLUMN2|
--------+--------+
1| 2|
1| 2|
2| 3|
3| 4|
4| 5|
5| 6|
Snowflake¶
CREATE OR REPLACE PROCEDURE myProcedure ()
RETURNS VARCHAR
LANGUAGE SQL
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"oracle"}}'
EXECUTE AS CALLER
AS
$$
BEGIN
--** SSC-PRF-0003 - FETCH INSIDE A LOOP IS CONSIDERED A COMPLEX PATTERN, THIS COULD DEGRADE SNOWFLAKE PERFORMANCE. **
INSERT INTO table2
(
SELECT
column1,
column2
FROM
table1
);
END;
$$;
COLUMN1| COLUMN2|
--------------------+-----------------------+
1.000000000000000000| 2.000000000000000000|
1.000000000000000000| 2.000000000000000000|
2.000000000000000000| 3.000000000000000000|
3.000000000000000000| 4.000000000000000000|
4.000000000000000000| 5.000000000000000000|
5.000000000000000000| 6.000000000000000000|
7. FORALL With UPDATE Statements¶
Oracle¶
CREATE OR REPLACE PROCEDURE myProcedure IS
CURSOR cursorVariable IS
SELECT * FROM table1;
TYPE collectionTypeDefinition IS TABLE OF table1%ROWTYPE;
collectionVariable collectionTypeDefinition;
BEGIN
OPEN cursorVariable;
LOOP
FETCH cursorVariable BULK COLLECT INTO collectionVariable limit 2;
EXIT WHEN collectionVariable.COUNT = 0;
FORALL forIndex IN collectionVariable.FIRST..collectionVariable.LAST
UPDATE table2 SET column1 = '54321' WHERE column2 = collectionVariable(forIndex).column2;
collectionVariable.DELETE;
END LOOP;
CLOSE cursorVariable;
END;
COLUMN1| COLUMN2|
--------+--------+
54321| 2|
Snowflake¶
CREATE OR REPLACE PROCEDURE myProcedure ()
RETURNS VARCHAR
LANGUAGE SQL
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"oracle"}}'
EXECUTE AS CALLER
AS
$$
BEGIN
--** SSC-PRF-0001 - THIS STATEMENT HAS USAGES OF CURSOR FETCH BULK OPERATIONS **
--** SSC-PRF-0003 - FETCH INSIDE A LOOP IS CONSIDERED A COMPLEX PATTERN, THIS COULD DEGRADE SNOWFLAKE PERFORMANCE. **
UPDATE table2
SET column1 = '54321'
FROM
(
SELECT
* FROM
table1) AS collectionVariable
WHERE
column2 = collectionVariable.column2;
END;
$$;
ambiguous column name 'COLUMN2'
8. FORALL With DELETE Statements¶
Oracle¶
CREATE OR REPLACE PROCEDURE myProcedure IS
CURSOR cursorVariable IS
SELECT * FROM table1;
TYPE collectionTypeDefinition IS TABLE OF table1%ROWTYPE;
collectionVariable collectionTypeDefinition;
BEGIN
OPEN cursorVariable;
LOOP
FETCH cursorVariable BULK COLLECT INTO collectionVariable limit 2;
EXIT WHEN collectionVariable.COUNT = 0;
FORALL forIndex IN collectionVariable.FIRST..collectionVariable.LAST
DELETE FROM table2 WHERE column2 = collectionVariable(forIndex).column2;
collectionVariable.DELETE;
END LOOP;
CLOSE cursorVariable;
END;
no data found
Snowflake¶
CREATE OR REPLACE PROCEDURE myProcedure ()
RETURNS VARCHAR
LANGUAGE SQL
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"oracle"}}'
EXECUTE AS CALLER
AS
$$
BEGIN
--** SSC-PRF-0001 - THIS STATEMENT HAS USAGES OF CURSOR FETCH BULK OPERATIONS **
--** SSC-PRF-0003 - FETCH INSIDE A LOOP IS CONSIDERED A COMPLEX PATTERN, THIS COULD DEGRADE SNOWFLAKE PERFORMANCE. **
DELETE FROM
table2
USING (
SELECT
* FROM
table1) collectionVariable
WHERE
table2.column2 = collectionVariable.column2;
END;
$$;
Query produced no results
Problemas conhecidos¶
Não foram encontrados problemas.
EWIs relacionados¶
SSC-EWI-0030: A instrução abaixo tem usos de SQL dinâmico.
SSC-EWI-0036: Tipo de dados convertido em outro tipo de dados.
SSC-EWI-0058: No momento, a funcionalidade não é compatível com o Snowflake Scripting.
SSC-EWI-0062: O uso do tipo personalizado foi alterado para variante.
SSC-EWI-OR0129: o atributo TYPE não pôde ser resolvido.
SSC-FDM-0006: A coluna de tipo de número pode não se comportar de forma semelhante no Snowflake.
SSC-FDM-OR0031: A cláusula de registro de erros em instruções DML não é suportada pelo Snowflake.
SSC-PRF-0001: Essa instrução tem usos de operações em massa de busca de cursor.
SSC-PRF-0003: A busca dentro de um loop é considerada um padrão complexo, o que pode prejudicar o desempenho do Snowflake.
LOOP¶
Descrição¶
A cada iteração da instrução básica LOOP
, suas instruções são executadas e o controle retorna ao topo do loop. A instrução LOOP
termina quando uma instrução dentro do loop transfere o controle para fora do loop ou levanta uma exceção.\ (Instrução BASIC LOOP da referência de linguagem Oracle PL/SQL)
LOOP statement... END LOOP [ label ] ;
LOOP
<statement>;
[ <statement>; ... ]
END LOOP [ <label> ] ;
O comportamento do Oracle BASIC LOOP
também pode ser modificado com o uso das instruções:
Amostra de padrões da origem¶
Caso simples de loop¶
Esse caso é funcionalmente equivalente.
Oracle
CREATE TABLE loop_testing_table
(
iterator VARCHAR2(5)
);
CREATE OR REPLACE PROCEDURE loop_procedure
IS
I NUMBER := 1;
J NUMBER := 10;
BEGIN
LOOP
EXIT WHEN I = J;
INSERT INTO loop_testing_table VALUES(TO_CHAR(I));
I := I+1;
END LOOP;
END;
CALL loop_procedure();
SELECT * FROM loop_testing_table;
ITERATOR|
--------+
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
Snowflake Scripting
CREATE OR REPLACE TABLE loop_testing_table
(
iterator VARCHAR(5)
)
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"oracle"}}'
;
CREATE OR REPLACE PROCEDURE loop_procedure ()
RETURNS VARCHAR
LANGUAGE SQL
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"oracle"}}'
EXECUTE AS CALLER
AS
$$
DECLARE
I NUMBER(38, 18) := 1;
J NUMBER(38, 18) := 10;
BEGIN
LOOP
IF (:I = :J) THEN
EXIT;
END IF;
INSERT INTO loop_testing_table
VALUES(TO_CHAR(:I));
I := :I +1;
END LOOP;
END;
$$;
CALL loop_procedure();
SELECT * FROM
loop_testing_table;
ITERATOR|
--------+
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
Known Issues
Não foram encontrados problemas.
Related EWIs
Sem EWIs relacionados.
OUTPUT PARAMETERS
Description
Um parâmetro de saída é um parâmetro cujo valor é passado do módulo de procedimento/função armazenado para o bloco de chamada PL/SQL. Como os parâmetros de saída não são compatíveis com o Snowflake Scripting, foi implementada uma solução para emular sua funcionalidade.
Sample Source Patterns
Tabela auxiliar de amostra
CREATE TABLE table01 (col1 NUMBER, col2 NUMBER);
CREATE OR REPLACE TABLE table01 (col1 NUMBER(38, 18) /*** SSC-FDM-0006 - NUMBER TYPE COLUMN MAY NOT BEHAVE SIMILARLY IN SNOWFLAKE. ***/,
col2 NUMBER(38, 18) /*** SSC-FDM-0006 - NUMBER TYPE COLUMN MAY NOT BEHAVE SIMILARLY IN SNOWFLAKE. ***/
)
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"oracle"}}'
;
Na declaração, as palavras-chave OUT
ou IN OUT
são removidas. A atribuição está sendo emitida da mesma forma que a entrada, mas para emular a funcionalidade do parâmetro de saída, algumas instruções estão sendo adicionadas.
Quando um procedimento com parâmetros de saída está sendo chamado em outro, algumas instruções são adicionadas para obter e atribuir o(s) valor(es) ao(s) respectivo(s) argumento(s).
Parâmetro de saída único
Oracle
-- Procedure with output parameter declaration
CREATE OR REPLACE PROCEDURE proc_with_single_output_parameters(
param1 OUT NUMBER
)
IS
BEGIN
param1 := 123;
END;
-- Procedure with output parameter being called
CREATE OR REPLACE PROCEDURE proc_calling_proc_with_single_output_parameters
IS
var1 NUMBER;
BEGIN
proc_with_single_output_parameters(var1);
INSERT INTO TABLE01 VALUES(var1, -1);
END;
Snowflake Scripting
-- Procedure with output parameter declaration
CREATE OR REPLACE PROCEDURE proc_with_single_output_parameters (param1 NUMBER(38, 18)
)
RETURNS VARIANT
LANGUAGE SQL
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"oracle"}}'
EXECUTE AS CALLER
AS
$$
BEGIN
param1 := 123;
RETURN param1;
END;
$$;
-- Procedure with output parameter being called
CREATE OR REPLACE PROCEDURE proc_calling_proc_with_single_output_parameters ()
RETURNS VARCHAR
LANGUAGE SQL
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"oracle"}}'
EXECUTE AS CALLER
AS
$$
DECLARE
var1 NUMBER(38, 18);
call_results VARIANT;
BEGIN
call_results := (
CALL
proc_with_single_output_parameters(:var1)
);
var1 := :call_results;
INSERT INTO TABLE01
VALUES(:var1, -1);
END;
$$;
Parâmetro de saída múltipla
Oracle
-- Procedure with output parameters declaration
CREATE OR REPLACE PROCEDURE proc_with_multiple_output_parameters(
param1 OUT NUMBER,
param2 IN OUT NUMBER
)
IS
BEGIN
param1 := 123;
param2 := 456;
END;
-- Procedure with output parameters being called
CREATE OR REPLACE PROCEDURE proc_calling_proc_with_multiple_output_parameters
IS
var1 NUMBER;
var2 NUMBER;
BEGIN
proc_with_multiple_output_parameters(var1, var2);
INSERT INTO TABLE01 VALUES(var1, var2);
END;
Snowflake Scripting
-- Procedure with output parameters declaration
CREATE OR REPLACE PROCEDURE proc_with_multiple_output_parameters (param1 NUMBER(38, 18), param2 NUMBER(38, 18)
)
RETURNS VARIANT
LANGUAGE SQL
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"oracle"}}'
EXECUTE AS CALLER
AS
$$
BEGIN
param1 := 123;
param2 := 456;
RETURN OBJECT_CONSTRUCT('param1', :param1, 'param2', :param2);
END;
$$;
-- Procedure with output parameters being called
--** SSC-FDM-0007 - MISSING DEPENDENT OBJECT "TABLE01" **
CREATE OR REPLACE PROCEDURE proc_calling_proc_with_multiple_output_parameters ()
RETURNS VARCHAR
LANGUAGE SQL
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"oracle"}}'
EXECUTE AS CALLER
AS
$$
DECLARE
var1 NUMBER(38, 18);
var2 NUMBER(38, 18);
call_results VARIANT;
BEGIN
call_results := (
CALL
proc_with_multiple_output_parameters(:var1, :var2)
);
var1 := :call_results:param1;
var2 := :call_results:param2;
INSERT INTO TABLE01
VALUES(:var1, :var2);
END;
$$;
Para verificar se a funcionalidade está sendo emulada corretamente, a consulta a seguir executará o procedimento e um SELECT
da tabela mencionada anteriormente.
Oracle
CALL proc_with_single_output_parameters();
CALL proc_with_multiple_output_parameters();
SELECT * FROM table01;
COL1|COL2
----+----
123 |-1
123 |456
Snowflake Scripting
CALL proc_with_single_output_parameters();
CALL proc_with_multiple_output_parameters();
SELECT * FROM table01;
COL1 | COL2
-----------------------+-----------------------
123.000000000000000000 | -1
123.000000000000000000 | 456.000000000000000000
Parâmetros de OUT para tipos de dados do cliente
Quando o parâmetro de saída é um tipo de cliente, o processo é semelhante ao de um tipo de dados normal.
Oracle
CREATE OR REPLACE PROCEDURE procedure_udtype_out_params (
p_employee_id NUMBER,
p_address OUT address_type
)
AS
BEGIN
-- Retrieve the employee's address based on the employee ID.
SELECT home_address INTO p_address
FROM employees
WHERE employee_id = p_employee_id;
END;
Snowflake Scripting
CREATE OR REPLACE PROCEDURE procedure_udtype_out_params (p_employee_id NUMBER(38, 18), p_address VARIANT /*** SSC-FDM-0015 - REFERENCED CUSTOM TYPE 'address_type' IN QUERY NOT FOUND, USAGES MAY BE AFFECTED ***/
)
RETURNS VARIANT
LANGUAGE SQL
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"oracle"}}'
EXECUTE AS CALLER
AS
$$
BEGIN
-- Retrieve the employee's address based on the employee ID.
SELECT home_address INTO
:p_address
FROM
employees
WHERE employee_id = :p_employee_id;
RETURN p_address;
END;
$$;
Known Issues
1. Procedures with output parameters inside packages may not work correctly
Atualmente, há um problema ao coletar as informações semânticas dos procedimentos que residem dentro dos pacotes, razão pela qual a transformação dos parâmetros de saída pode funcionar parcialmente ou não funcionar. Já existe um trabalho em andamento para resolver esse problema.
2. Some data types may not work properly
Como visto na transformação, ao recuperar o valor dos procedimentos chamados, é realizada uma conversão implícita de VARIANT para o tipo especificado pela variável. Como há muitos tipos de dados possíveis, algumas conversões podem falhar ou conter dados diferentes.
Related EWIs
SSC-FDM-0006: A coluna de tipo de número pode não se comportar de forma semelhante no Snowflake.
SSC-FDM-0007: Elemento com dependências ausentes.
SSC-FDM-0015: Tipo de dados não reconhecido.
PROCEDURE CALL
Nota
Algumas partes do código de saída foram omitidas por motivos de clareza.
Descrição¶
Esta seção descreve a sintaxe para invocações de subprogramas em blocos PL, como procedimentos ou blocos anônimos.
Para obter mais informações sobre esse assunto, consulte a documentação de subprogramas da Oracle: (Instrução Invocation de subprogramas da referência de linguagem Oracle PL/SQL)
As chamadas de procedimento podem ser migradas para o Snowflake, desde que não haja parâmetros opcionais e que a ordem deles corresponda aos parâmetros formais. Observe que as invocações de procedimentos são migradas para uma instrução Call.
<subprogram invocation> := subprogram_name [ ( [ parameter [, parameter]... ] ) ]
<parameter> := {
<actual parameter>
| <formal parameter name> => <actual parameter>
}
O Snowflake Scripting tem suporte para essa instrução, embora com algumas diferenças funcionais.
<subprogram invocation> := CALL subprogram_name [ ( [ parameter [, parameter]... ] ) ]
<parameter> := {
<actual parameter>
| <formal parameter name> => <actual parameter>
}
Amostra de padrões da origem¶
Nota
Considere a próxima tabela e o procedimento para os exemplos abaixo.
CREATE TABLE procedure_call_test_table(
col1 INTEGER
);
-- Simple Called procedure
CREATE OR REPLACE PROCEDURE called_procedure (param1 INTEGER)
AS
BEGIN
INSERT INTO procedure_call_test_table VALUES (param1);
END;
CREATE OR REPLACE TABLE procedure_call_test_table (
col1 INTEGER
)
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},"attributes":{"component":"oracle"}}'
;
-- Simple Called procedure
CREATE OR REPLACE PROCEDURE called_procedure (param1 INTEGER)
RETURNS VARCHAR
LANGUAGE SQL
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},"attributes":{"component":"oracle"}}'
EXECUTE AS CALLER
AS
$$
BEGIN
INSERT INTO procedure_call_test_table
VALUES (:param1);
END;
$$;
Chamada simples¶
Oracle¶
CREATE OR REPLACE PROCEDURE simple_calling_procedure
AS
BEGIN
called_procedure(1);
END;
CALL simple_calling_procedure();
SELECT * FROM procedure_call_test_table;
COL1|
----+
1|
Script Snowflake¶
CREATE OR REPLACE PROCEDURE simple_calling_procedure ()
RETURNS VARCHAR
LANGUAGE SQL
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"oracle"}}'
EXECUTE AS CALLER
AS
$$
BEGIN
CALL
called_procedure(1);
END;
$$;
CALL simple_calling_procedure();
--** SSC-FDM-0007 - MISSING DEPENDENT OBJECT "procedure_call_test_table" **
SELECT * FROM
procedure_call_test_table;
COL1|
----+
1|
Chamada de um procedimento com um parâmetro opcional¶
Aviso
Essa amostra contém intervenção manual para algumas diferenças funcionais e é usada para explicá-las. Para obter mais informações sobre essas diferenças, consulte a seção Problemas conhecidos abaixo.
Oracle¶
-- Procedure with optional parameters
CREATE OR REPLACE PROCEDURE proc_optional_parameters (param1 INTEGER, param2 INTEGER := 8, param3 INTEGER)
AS
BEGIN
INSERT INTO procedure_call_test_table VALUES (param1);
INSERT INTO procedure_call_test_table VALUES (param2);
INSERT INTO procedure_call_test_table VALUES (param3);
END;
CREATE OR REPLACE PROCEDURE calling_procedure
AS
BEGIN
-- positional convention
proc_optional_parameters(1, 2, 3);
-- named convention
proc_optional_parameters(param1 => 4, param2 => 5, param3 => 6);
-- named convention, second gets ommited
proc_optional_parameters(param1 => 7, param3 => 9);
-- named convention, different order
proc_optional_parameters(param3 => 12, param1 => 10, param2 => 11);
END;
CALL calling_procedure();
SELECT * FROM procedure_call_test_table;
COL1|
----+
1|
2|
3|
4|
5|
6|
7|
8|
9|
10|
11|
12|
Script Snowflake¶
-- Procedure with optional parameters
CREATE OR REPLACE PROCEDURE proc_optional_parameters
!!!RESOLVE EWI!!! /*** SSC-EWI-0002 - DEFAULT PARAMETERS MAY NEED TO BE REORDERED. SNOWFLAKE ONLY SUPPORTS DEFAULT PARAMETERS AT THE END OF THE PARAMETERS DECLARATIONS ***/!!!
(param1 INTEGER, param2 INTEGER DEFAULT 8, param3 INTEGER)
RETURNS VARCHAR
LANGUAGE SQL
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},"attributes":{"component":"oracle"}}'
EXECUTE AS CALLER
AS
$$
BEGIN
INSERT INTO procedure_call_test_table
VALUES (:param1);
INSERT INTO procedure_call_test_table
VALUES (:param2);
INSERT INTO procedure_call_test_table
VALUES (:param3);
END;
$$;
CREATE OR REPLACE PROCEDURE calling_procedure ()
RETURNS VARCHAR
LANGUAGE SQL
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},"attributes":{"component":"oracle"}}'
EXECUTE AS CALLER
AS
$$
BEGIN
CALL
-- positional convention
proc_optional_parameters(1, 2, 3);
CALL
-- named convention
proc_optional_parameters(param1 => 4, param2 => 5, param3 => 6);
CALL
-- named convention, second gets ommited
proc_optional_parameters(param1 => 7, param3 => 9);
CALL
-- named convention, different order
proc_optional_parameters(param1 => 10, param2 => 11, param3 => 12);
END;
$$;
CALL calling_procedure();
SELECT * FROM
procedure_call_test_table;
COL1|
----+
1|
2|
3|
4|
5|
6|
7|
8|
9|
10|
11|
12|
Problemas conhecidos¶
1. Calling Subprograms with default values is not supported¶
O Snowflake não suporta a definição de valores padrão para parâmetros. Portanto, eles precisarão ser preenchidos em cada chamada.
2. Named parameters are accepted, but not functionally equivalent¶
Esses parâmetros não causarão nenhum erro de compilação quando executados no Snowflake; no entanto, as chamadas ainda os colocam de forma posicional. Por esse motivo, a ordem desses parâmetros precisa ser verificada. O SnowConvert não oferece suporte à verificação nem à reordenação desses parâmetros.
3. Calling Subprograms with Out Parameters is not supported¶
O Snowflake não tem suporte para modos de parâmetro, mas uma solução está sendo implementada para emular sua funcionalidade. Para obter mais informações sobre a transformação dos parâmetros de saída, consulte o seguinte artigo Parâmetros de saída.
EWIs relacionados¶
SSC-EWI-0002: Os parâmetros padrão podem precisar ser reordenados.
SSC-FDM-0007: Elemento com dependências ausentes.
RAISE¶
Descrição¶
A instrução RAISE
levanta explicitamente uma exceção.
Fora de um manipulador de exceção, você deve especificar o nome da exceção. Dentro de um manipulador de exceção, se o nome da exceção for omitido, a instrução RAISE
levanta novamente a exceção atual. (Instrução Raise da referência de linguagem Oracle PL/SQL)
A instrução é totalmente compatível com o Snowflake Scripting, mas você deve levar em conta que pode haver algumas diferenças quando houver uma instrução de Commit e Rollback.
RAISE <exception_name> ;
O Snowflake Scripting tem suporte para essa instrução.
RAISE <exception_name> ;
Amostra de padrões da origem¶
Lançamento de exceção simples¶
Oracle¶
CREATE OR REPLACE PROCEDURE simple_exception_throw_handle(param1 INTEGER)
IS
my_exception EXCEPTION;
my_other_exception EXCEPTION;
BEGIN
IF param1 > 0
THEN RAISE my_exception;
END IF;
EXCEPTION
WHEN my_exception THEN
IF param1 = 1
THEN RAISE;
END IF;
RAISE my_other_exception;
END;
--Completes without issue
CALL simple_exception_throw_handle(0);
--Throws my_exception
CALL simple_exception_throw_handle(1);
--Throws my_exception, catches then raises second my_other_exception
CALL simple_exception_throw_handle(2);
Call completed.
-----------------------------------------------------------------------
Error starting at line : 31 in command -
CALL simple_exception_throw_handle(1)
Error report -
ORA-06510: PL/SQL: unhandled user-defined exception
ORA-06512: at "SYSTEM.SIMPLE_EXCEPTION_THROW_HANDLE", line 12
ORA-06512: at "SYSTEM.SIMPLE_EXCEPTION_THROW_HANDLE", line 7
ORA-06512: at line 1
06510. 00000 - "PL/SQL: unhandled user-defined exception"
*Cause: A user-defined exception was raised by PL/SQL code, but
not handled.
*Action: Fix the problem causing the exception or write an exception
handler for this condition. Or you may need to contact your
application administrator or DBA.
-----------------------------------------------------------------------
Error starting at line : 33 in command -
CALL simple_exception_throw_handle(2)
Error report -
ORA-06510: PL/SQL: unhandled user-defined exception
ORA-06512: at "SYSTEM.SIMPLE_EXCEPTION_THROW_HANDLE", line 14
ORA-06510: PL/SQL: unhandled user-defined exception
ORA-06512: at "SYSTEM.SIMPLE_EXCEPTION_THROW_HANDLE", line 7
ORA-06512: at line 1
06510. 00000 - "PL/SQL: unhandled user-defined exception"
*Cause: A user-defined exception was raised by PL/SQL code, but
not handled.
*Action: Fix the problem causing the exception or write an exception
handler for this condition. Or you may need to contact your
application administrator or DBA.
Script Snowflake¶
CREATE OR REPLACE PROCEDURE simple_exception_throw_handle (param1 INTEGER)
RETURNS VARCHAR
LANGUAGE SQL
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"oracle"}}'
EXECUTE AS CALLER
AS
$$
DECLARE
my_exception EXCEPTION;
my_other_exception EXCEPTION;
BEGIN
IF (:param1 > 0) THEN
RAISE my_exception;
END IF;
EXCEPTION
WHEN my_exception THEN
IF (:param1 = 1) THEN
RAISE;
END IF;
RAISE my_other_exception;
END;
$$;
--Completes without issue
CALL simple_exception_throw_handle(0);
--Throws my_exception
CALL simple_exception_throw_handle(1);
--Throws my_exception, catches then raises second my_other_exception
CALL simple_exception_throw_handle(2);
Call Completed
-----------------------------------------------------------------------
Uncaught exception of type 'MY_EXCEPTION' on line 7 at position 9
-----------------------------------------------------------------------
Uncaught exception of type 'MY_OTHER_EXCEPTION' on line 14 at position 9
Problemas conhecidos¶
Não foram encontrados problemas.
EWIs relacionados¶
Sem EWIs relacionados.
RAISE_APPICATION_ERROR¶
Descrição geral¶
O procedimento RAISE_APPLICATION_ERROR
permite emitir mensagens de erro ORA-
definidas pelo usuário a partir de subprogramas armazenados. Dessa forma, você pode relatar erros ao aplicativo e evitar o retorno de exceções não tratadas (Documentação do Oracle
).
Sintaxe do Oracle¶
raise_application_error(
error_number, message[, {TRUE | FALSE}]);
Nota
O error_number
é um número inteiro negativo no intervalo -20000 .. -20999 e message
é uma cadeia de caracteres de até 2048 bytes.
Se o terceiro parâmetro opcional for TRUE, o erro será colocado na pilha de erros anteriores. Se o parâmetro for FALSE (o padrão), o erro substitui todos os erros anteriores.
A instrução equivalente no Snowflake é a cláusula RAISE. No entanto, é necessário declarar a exceção definida pelo usuário como uma variável antes de chamar a instrução RAISE para ela.
Sintaxe do Snowflake¶
<exception_name> EXCEPTION [ ( <exception_number> , '<exception_message>' ) ] ;
Nota
Para obter mais informações, consulte a documentação do Snowflake a seguir.
Amostra de padrões da origem¶
1. Exception in functions without declaring section¶
Nesse cenário, a função sem uma seção de declaração é convertida em um procedimento com a declaração de exceção. Observe que:
O nome da variável de exceção é declarado em letras maiúsculas.
O nome da variável de exceção é baseado na descrição e o final é composto por um nome de código de exceção seguido por um número consecutivo.
A seção de declaração é criada mesmo que a função ou o procedimento inicial não a contenha.
Oracle
CREATE OR REPLACE FUNCTION TEST(
SAMPLE_A IN NUMBER DEFAULT NULL,
SAMPLE_B IN NUMBER DEFAULT NULL
)
RETURN NUMBER
AS
BEGIN
raise_application_error(-20001, 'First exception message', FALSE);
raise_application_error(-20002, 'Second exception message');
RETURN 1;
END TEST;
ORA-20001: First exception message
Snowflake
--** SSC-FDM-0029 - USER DEFINED FUNCTION WAS TRANSFORMED TO SNOWFLAKE PROCEDURE **
CREATE OR REPLACE PROCEDURE TEST(
SAMPLE_A NUMBER(38, 18) DEFAULT NULL,
SAMPLE_B NUMBER(38, 18) DEFAULT NULL
)
RETURNS NUMBER(38, 18)
LANGUAGE SQL
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},"attributes":{"component":"oracle"}}'
EXECUTE AS CALLER
AS
$$
DECLARE
FIRST_EXCEPTION_MESSAGE_EXCEPTION_CODE_0 EXCEPTION (-20001, 'FIRST EXCEPTION MESSAGE');
SECOND_EXCEPTION_MESSAGE_EXCEPTION_CODE_1 EXCEPTION (-20002, 'SECOND EXCEPTION MESSAGE');
BEGIN
--** SSC-FDM-OR0011 - ADD TO STACK OF ERRORS IS NOT SUPPORTED, BOOLEAN ARGUMENT FALSE WAS REMOVED. **
RAISE FIRST_EXCEPTION_MESSAGE_EXCEPTION_CODE_0;
RAISE SECOND_EXCEPTION_MESSAGE_EXCEPTION_CODE_1;
RETURN 1;
END;
$$;
FIRST EXCEPTION MESSAGE
2. Exception code number outside limits¶
O exemplo a seguir mostra a conversão comentada no corpo do procedimento. Isso ocorre porque o código está fora dos limites de código aplicáveis no Snowflake. A solução é alterar o código de exceção para um código disponível na seção de consulta.
Oracle
CREATE OR REPLACE FUNCTION TEST(
SAMPLE_A IN NUMBER DEFAULT NULL,
SAMPLE_B IN NUMBER DEFAULT NULL
)
RETURN NUMBER
AS
BEGIN
raise_application_error(-20000, 'My exception message');
RETURN 1;
END TEST;
ORA-20000: My exception message
Snowflake
--** SSC-FDM-0029 - USER DEFINED FUNCTION WAS TRANSFORMED TO SNOWFLAKE PROCEDURE **
CREATE OR REPLACE PROCEDURE TEST(
SAMPLE_A NUMBER(38, 18) DEFAULT NULL,
SAMPLE_B NUMBER(38, 18) DEFAULT NULL
)
RETURNS NUMBER(38, 18)
LANGUAGE SQL
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},"attributes":{"component":"oracle"}}'
EXECUTE AS CALLER
AS
$$
DECLARE
MY_EXCEPTION_MESSAGE_EXCEPTION_CODE_0 EXCEPTION (-20000, 'MY EXCEPTION MESSAGE');
BEGIN
!!!RESOLVE EWI!!! /*** SSC-EWI-OR0099 - EXCEPTION CODE NUMBER EXCEEDS SNOWFLAKE SCRIPTING LIMITS ***/!!!
RAISE MY_EXCEPTION_MESSAGE_EXCEPTION_CODE_0;
RETURN 1;
END;
$$;
Invalid error code '-20,000'. Must be between -20,999 and -20,000
3. Exception stack functionality¶
A funcionalidade da pilha de exceções não é compatível com o Snowflake e foi removida da declaração de exceções.
Oracle
CREATE OR REPLACE FUNCTION TEST(
SAMPLE_A IN NUMBER DEFAULT NULL,
SAMPLE_B IN NUMBER DEFAULT NULL
)
RETURN NUMBER
AS
BEGIN
raise_application_error(-20001, 'My exception message', TRUE);
RETURN 1;
END TEST;
ORA-20001: My exception message
Snowflake
--** SSC-FDM-0029 - USER DEFINED FUNCTION WAS TRANSFORMED TO SNOWFLAKE PROCEDURE **
CREATE OR REPLACE PROCEDURE TEST(
SAMPLE_A NUMBER(38, 18) DEFAULT NULL,
SAMPLE_B NUMBER(38, 18) DEFAULT NULL
)
RETURNS NUMBER(38, 18)
LANGUAGE SQL
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},"attributes":{"component":"oracle"}}'
EXECUTE AS CALLER
AS
$$
DECLARE
MY_EXCEPTION_MESSAGE_EXCEPTION_CODE_0 EXCEPTION (-20001, 'MY EXCEPTION MESSAGE');
BEGIN
--** SSC-FDM-OR0011 - ADD TO STACK OF ERRORS IS NOT SUPPORTED, BOOLEAN ARGUMENT TRUE WAS REMOVED. **
RAISE MY_EXCEPTION_MESSAGE_EXCEPTION_CODE_0;
RETURN 1;
END;
$$;
MY EXCEPTION MESSAGE
4. Multiple exceptions with the same exception code¶
Várias exceções com o mesmo nome podem coexistir na seção de declaração e nas instruções de aumento.
Oracle
CREATE OR REPLACE FUNCTION TEST(
SAMPLE_A IN NUMBER DEFAULT NULL,
SAMPLE_B IN NUMBER DEFAULT NULL
)
RETURN NUMBER
AS
BEGIN
IF TRUE THEN
raise_application_error(-20001, 'The first exception');
ELSE
raise_application_error(-20001, 'Other exception inside');
END IF;
RETURN 1;
END TEST;
ORA-20000: The first exception
Snowflake
--** SSC-FDM-0029 - USER DEFINED FUNCTION WAS TRANSFORMED TO SNOWFLAKE PROCEDURE **
CREATE OR REPLACE PROCEDURE TEST(
SAMPLE_A NUMBER(38, 18) DEFAULT NULL,
SAMPLE_B NUMBER(38, 18) DEFAULT NULL
)
RETURNS NUMBER(38, 18)
LANGUAGE SQL
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},"attributes":{"component":"oracle"}}'
EXECUTE AS CALLER
AS
$$
DECLARE
THE_FIRST_EXCEPTION_EXCEPTION_CODE_0 EXCEPTION (-20001, 'THE FIRST EXCEPTION');
OTHER_EXCEPTION_INSIDE_EXCEPTION_CODE_1 EXCEPTION (-20001, 'OTHER EXCEPTION INSIDE');
BEGIN
IF (TRUE) THEN
RAISE THE_FIRST_EXCEPTION_EXCEPTION_CODE_0;
ELSE
RAISE OTHER_EXCEPTION_INSIDE_EXCEPTION_CODE_1;
END IF;
RETURN 1;
END;
$$;
THE FIRST EXCEPTION
Problemas conhecidos¶
A função SQLREM pode ser revisada.
O número do código de exceção fora dos limites aplicáveis no Snowflake deve ser alterado para um código de exceção disponível.
Não há suporte para adicionar a uma pilha de erros.
EWIs relacionados¶
SSC-EWI-OR0099: O código de exceção excede o limite do Snowflake Scripting.
SSC-FDM-0029: A função definida pelo usuário foi transformada em um procedimento do Snowflake.
SSC-FDM-OR0011: O argumento booliano foi removido porque não há suporte para as opções «add to stack».
UDF CALL¶
Nota
Algumas partes do código de saída foram omitidas por motivos de clareza.
Descrição¶
Como é amplamente reconhecido, as funções não escalares definidas pelo usuário (UDFs) no Oracle são convertidas em procedimentos armazenados Snowflake para acomodar funcionalidades mais complexas.
Essa transformação também altera a forma como a função é invocada, passando de uma chamada de função tradicional para uma chamada de procedimento armazenado.
Para obter mais detalhes sobre a invocação de procedimentos armazenados, consulte a documentação disponível aqui: PROCEDURE CALL.
Amostra de padrões da origem¶
Nota
Considere a função e as tabelas a seguir para os exemplos abaixo.
CREATE OR REPLACE FUNCTION sum_to_varchar_function(p_number1 IN NUMBER, p_number2 IN NUMBER)
RETURN VARCHAR
IS
result VARCHAR(100);
BEGIN
result := TO_CHAR(p_number1 + p_number2);
RETURN result;
END sum_to_varchar_function;
CREATE TABLE example_table (
id NUMBER,
column1 NUMBER
);
INSERT INTO example_table VALUES (1, 15);
CREATE TABLE result_table (
id NUMBER,
result_col VARCHAR(100)
);
CREATE OR REPLACE FUNCTION sum_to_varchar_function (p_number1 NUMBER(38, 18), p_number2 NUMBER(38, 18))
RETURNS VARCHAR
LANGUAGE SQL
COMMENT = '{ "origin": "sf_sc", "name": "snowconvert", "version": { "major": 0, "minor": 0, "patch": "0" }, "attributes": { "component": "oracle", "convertedOn": "11/14/2024", "domain": "test" }}'
AS
$$
WITH declaration_variables_cte1 AS
(
SELECT
TO_CHAR(p_number1 + p_number2) AS
result
)
SELECT
result
FROM
declaration_variables_cte1
$$;
CREATE OR REPLACE TABLE example_table (
id NUMBER(38, 18) /*** SSC-FDM-0006 - NUMBER TYPE COLUMN MAY NOT BEHAVE SIMILARLY IN SNOWFLAKE. ***/,
column1 NUMBER(38, 18) /*** SSC-FDM-0006 - NUMBER TYPE COLUMN MAY NOT BEHAVE SIMILARLY IN SNOWFLAKE. ***/
)
COMMENT = '{ "origin": "sf_sc", "name": "snowconvert", "version": { "major": 0, "minor": 0, "patch": "0" }, "attributes": { "component": "oracle", "convertedOn": "11/14/2024", "domain": "test" }}'
;
INSERT INTO example_table
VALUES (1, 15);
CREATE OR REPLACE TABLE result_table (
id NUMBER(38, 18) /*** SSC-FDM-0006 - NUMBER TYPE COLUMN MAY NOT BEHAVE SIMILARLY IN SNOWFLAKE. ***/,
result_col VARCHAR(100)
)
COMMENT = '{ "origin": "sf_sc", "name": "snowconvert", "version": { "major": 0, "minor": 0, "patch": "0" }, "attributes": { "component": "oracle", "convertedOn": "11/14/2024", "domain": "test" }}'
;
Chamada UDF¶
Oracle¶
CREATE OR REPLACE PROCEDURE procedure_calling_function(param1 IN NUMBER)
IS
result_value VARCHAR(200);
BEGIN
result_value := sum_to_varchar_function(3, param1);
INSERT INTO result_table VALUES (1, result_value);
END;
BEGIN
procedure_calling_function(5);
END;
ID RESULT_COL
1 8
Script Snowflake¶
CREATE OR REPLACE PROCEDURE procedure_calling_function (param1 NUMBER(38, 18))
RETURNS VARCHAR
LANGUAGE SQL
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},"attributes":{"component":"oracle"}}'
EXECUTE AS CALLER
AS
$$
DECLARE
result_value VARCHAR(200);
BEGIN
result_value := sum_to_varchar_function(3, :param1) !!!RESOLVE EWI!!! /*** SSC-EWI-0073 - PENDING FUNCTIONAL EQUIVALENCE REVIEW FOR 'sum_to_varchar_function' NODE ***/!!!;
INSERT INTO result_table
VALUES (1, :result_value);
END;
$$;
DECLARE
call_results VARIANT;
BEGIN
CALL
procedure_calling_function(5);
RETURN call_results;
END;
ID RESULT_COL
1 8
Chamada UDF dentro de uma consulta¶
Quando uma chamada de função é incorporada em uma consulta, o processo de invocação se torna mais complexo devido à limitação do Snowflake de não poder chamar procedimentos diretamente nas consultas. Para superar essa limitação, a invocação do procedimento é movida para fora da consulta e o resultado é atribuído a uma variável. Essa variável é, então, referenciada na consulta, alcançando assim a equivalência funcional. Essa abordagem permite a execução de comportamentos mais complexos dentro das consultas do Snowflake e, ao mesmo tempo, obedece às restrições processuais.
Oracle¶
CREATE OR REPLACE PROCEDURE procedure_calling_function(param1 IN NUMBER)
IS
result_value VARCHAR(200);
result_value2 VARCHAR(200);
BEGIN
SELECT
sum_to_varchar_function(1, param1) AS result_column,
sum_to_varchar_function(2, param1) AS result_column2
INTO result_value, result_value2
FROM example_table ext;
INSERT INTO result_table VALUES (1, result_value);
INSERT INTO result_table VALUES (2, result_value2);
END;
BEGIN
procedure_calling_function(5);
END;
ID RESULT_COL
1 6
2 7
Script Snowflake¶
CREATE OR REPLACE PROCEDURE procedure_calling_function (param1 NUMBER(38, 18))
RETURNS VARCHAR
LANGUAGE SQL
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},"attributes":{"component":"oracle"}}'
EXECUTE AS CALLER
AS
$$
DECLARE
result_value VARCHAR(200);
result_value2 VARCHAR(200);
BEGIN
SELECT
sum_to_varchar_function(1, :param1) !!!RESOLVE EWI!!! /*** SSC-EWI-0073 - PENDING FUNCTIONAL EQUIVALENCE REVIEW FOR 'sum_to_varchar_function' NODE ***/!!! AS result_column,
sum_to_varchar_function(2, :param1) !!!RESOLVE EWI!!! /*** SSC-EWI-0073 - PENDING FUNCTIONAL EQUIVALENCE REVIEW FOR 'sum_to_varchar_function' NODE ***/!!! AS result_column2
INTO
:result_value,
:result_value2
FROM
example_table ext;
INSERT INTO result_table
VALUES (1, :result_value);
INSERT INTO result_table
VALUES (2, :result_value2);
END;
$$;
DECLARE
call_results VARIANT;
BEGIN
CALL
procedure_calling_function(5);
RETURN call_results;
END;
ID RESULT_COL
1 6
2 7
Problemas conhecidos¶
1. Unsupported Usage of UDFs in Queries with Query Dependencies¶
Ao chamar funções definidas pelo usuário (UDFs) em consultas com dependências de consultas, não há suporte para cenários que envolvam funções incorporadas com colunas como argumentos. Essa limitação ocorre porque os valores das colunas não podem ser acessados de fora da consulta. Exemplos de cenários sem suporte incluem:
BEGIN
SELECT
sum_to_varchar_function(ext.col1, ext.col2) -- columns as arguments not supported
INTO
result_value
FROM example_table ext;
END;
\ Os cenários compatíveis incluem chamadas de função com outros tipos de argumentos, como valores literais, variáveis externas ou parâmetros. Por exemplo:
BEGIN
SELECT
sum_to_varchar_function(100, param1)
INTO
result_value
FROM example_table ext;
END;
Nos cenários suportados, a função pode ser efetivamente migrada.
EWIs relacionados¶
SSC-EWI-0073: Revisão de equivalência funcional pendente.
SSC-FDM-0006: A coluna de tipo de número pode não se comportar de forma semelhante no Snowflake.
SSC-FDM-0029: A função definida pelo usuário foi transformada em um procedimento do Snowflake.
WHILE¶
Descrição¶
A instrução WHILE
LOOP
executa uma ou mais instruções enquanto uma condição é TRUE
.\ (Instrução WHILE da referência de linguagem Oracle PL/SQL)
WHILE boolean_expression
LOOP statement... END LOOP [ label ] ;
WHILE ( <condition> ) { DO | LOOP }
<statement>;
[ <statement>; ... ]
END { WHILE | LOOP } [ <label> ] ;
O comportamento do Oracle WHILE
também pode ser modificado com o uso das instruções:
Amostra de padrões da origem¶
Caso simples de While¶
Esse caso é funcionalmente equivalente.
Oracle
CREATE TABLE while_testing_table
(
iterator VARCHAR2(5)
);
CREATE OR REPLACE PROCEDURE while_procedure
IS
I NUMBER := 1;
J NUMBER := 10;
BEGIN
WHILE I <> J LOOP
INSERT INTO while_testing_table VALUES(TO_CHAR(I));
I := I+1;
END LOOP;
END;
CALL while_procedure();
SELECT * FROM while_testing_table;
ITERATOR|
--------+
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
Snowflake Scripting
CREATE OR REPLACE TABLE while_testing_table
(
iterator VARCHAR(5)
)
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"oracle"}}'
;
CREATE OR REPLACE PROCEDURE while_procedure ()
RETURNS VARCHAR
LANGUAGE SQL
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"oracle"}}'
EXECUTE AS CALLER
AS
$$
DECLARE
I NUMBER(38, 18) := 1;
J NUMBER(38, 18) := 10;
BEGIN
WHILE (:I <> :J) LOOP
INSERT INTO while_testing_table
VALUES(TO_CHAR(:I));
I := :I +1;
END LOOP;
END;
$$;
CALL while_procedure();
SELECT * FROM
while_testing_table;
ITERATOR|
--------+
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
Known Issues
Não foram encontrados problemas.
Related EWIs
Sem EWIs relacionados.
CURSOR
Description
Nota
Para obter mais informações sobre a declaração Cursor, veja aqui.
Esta seção aborda a referência de conversão para Cursor explícito do Oracle. Para as Variáveis de Cursor do Oracle, não há equivalente no Snowflake Scripting.
Nota
Algumas partes do código de saída foram omitidas por motivos de clareza.
Cursores são ponteiros que permitem aos usuários iterar pelos resultados da consulta. Para obter mais informações sobre cursores Oracle, veja aqui.
Definição de cursor
CURSOR cursor
[ ( cursor_parameter_dec [, cursor_parameter_dec ]... )]
[ RETURN rowtype] IS select_statement ;
Cursor Open
OPEN cursor [ ( cursor_parameter [ [,] actual_cursor_parameter ]... ) ] ;
Cursor Fetch
FETCH { cursor | cursor_variable | :host_cursor_variable }
{ into_clause | bulk_collect_into_clause [ LIMIT numeric_expression ] } ;
Cursor Close
CLOSE { cursor | cursor_variable | :host_cursor_variable } ;
Atributos de cursor
named_cursor%{ ISOPEN | FOUND | NOTFOUND | ROWCOUNT }
Cursor FOR Loop
[ FOR record IN
{ cursor [ ( cursor_parameter_dec
[ [,] cursor_parameter_dec ]... )]
| ( select_statement )
}
LOOP statement... END LOOP [label] ;
O Snowflake Scripting oferece suporte a cursores, mas tem menos funcionalidades em comparação com o Oracle. Para obter mais informações sobre esses cursores, veja aqui.
Declaração de cursor
<cursor_name> CURSOR FOR <query>
Cursor Open
OPEN <cursor_name> [ USING (bind_variable_1 [, bind_variable_2 ...] ) ] ;
Cursor Fetch
FETCH <cursor_name> INTO <variable> [, <variable> ... ] ;
Cursor Close
CLOSE <cursor_name> ;
Cursor FOR Loop
FOR <row_variable> IN <cursor_name> DO
statement;
[ statement; ... ]
END FOR [ <label> ] ;
Amostra de padrões da origem¶
1. Basic cursor example¶
CREATE OR REPLACE PROCEDURE basic_cursor_sample AS
var1 VARCHAR(20);
CURSOR cursor1 IS SELECT region_name FROM hr.regions ORDER BY region_name;
BEGIN
OPEN cursor1;
FETCH cursor1 INTO var1;
CLOSE cursor1;
END;
CREATE OR REPLACE PROCEDURE basic_cursor_sample ()
RETURNS VARCHAR
LANGUAGE SQL
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"oracle"}}'
EXECUTE AS CALLER
AS
$$
DECLARE
var1 VARCHAR(20);
cursor1 CURSOR
FOR
SELECT region_name FROM
hr.regions
ORDER BY region_name;
BEGIN
OPEN cursor1;
FETCH cursor1 INTO
:var1;
CLOSE cursor1;
END;
$$;
2. Explicit Cursor For Loop¶
CREATE OR REPLACE PROCEDURE explicit_cursor_for_sample AS
CURSOR cursor1 IS SELECT region_name FROM hr.regions ORDER BY region_name;
BEGIN
FOR r1 IN cursor1 LOOP
NULL;
END LOOP;
END;
CREATE OR REPLACE PROCEDURE explicit_cursor_for_sample ()
RETURNS VARCHAR
LANGUAGE SQL
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},"attributes":{"component":"oracle"}}'
EXECUTE AS CALLER
AS
$$
DECLARE
cursor1 CURSOR
FOR
SELECT region_name FROM
hr.regions
ORDER BY region_name;
BEGIN
OPEN cursor1;
--** SSC-PRF-0004 - THIS STATEMENT HAS USAGES OF CURSOR FOR LOOP **
FOR r1 IN cursor1 DO
NULL;
END FOR;
CLOSE cursor1;
END;
$$;
3. Implicit Cursor For Loop¶
CREATE OR REPLACE PROCEDURE implicit_cursor_for_sample AS
BEGIN
FOR r1 IN (SELECT region_name FROM hr.regions ORDER BY region_name) LOOP
NULL;
END LOOP;
END;
CREATE OR REPLACE PROCEDURE implicit_cursor_for_sample ()
RETURNS VARCHAR
LANGUAGE SQL
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"oracle"}}'
EXECUTE AS CALLER
AS
$$
BEGIN
LET temporary_for_cursor_0 CURSOR
FOR
(SELECT region_name FROM
hr.regions
ORDER BY region_name);
--** SSC-PRF-0004 - THIS STATEMENT HAS USAGES OF CURSOR FOR LOOP **
FOR r1 IN temporary_for_cursor_0 DO
NULL;
END FOR;
END;
$$;
4. Parameterized Cursor¶
Você pode usar «?» Na condição de filtro do cursor, na seção de instrução, defina a variável bind. Ao abrir o cursor, podemos adicionar a sintaxe adicional «USING <bind_variable_1 >» para passar a variável bind.
Abaixo estão alguns exemplos de cenários que podem ocorrer no uso de parâmetros em cursores:
4.1 Exemplo parametrizado de cursor básico¶
CREATE OR REPLACE PROCEDURE parameterized_cursor_for_sample AS
CURSOR cursor1 (low number, high IN number) IS
SELECT region_name FROM hr.regions WHERE region_id BETWEEN low AND high;
BEGIN
OPEN cursor1(3,5);
CLOSE cursor1;
END;
CREATE OR REPLACE PROCEDURE parameterized_cursor_for_sample ()
RETURNS VARCHAR
LANGUAGE SQL
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},"attributes":{"component":"oracle"}}'
EXECUTE AS CALLER
AS
$$
DECLARE
cursor1 CURSOR
FOR
SELECT region_name FROM
hr.regions
WHERE region_id BETWEEN ? AND ?;
BEGIN
OPEN cursor1 USING (3, 5);
CLOSE cursor1;
END;
$$;
4.2 Cursores parametrizados com vários parâmetros de envio¶
CREATE OR REPLACE PROCEDURE parameterized_cursor_for_sample AS
CURSOR cursor1 (low number DEFAULT 2, high IN number DEFAULT 7) IS
SELECT region_name FROM hr.regions
WHERE region_id BETWEEN low AND high OR low < 0;
BEGIN
OPEN cursor1(3,5);
OPEN cursor1(3);
OPEN cursor1;
OPEN cursor1(high => 15, low => 5);
OPEN cursor1(high => 15);
CLOSE cursor1;
END;
CREATE OR REPLACE PROCEDURE parameterized_cursor_for_sample ()
RETURNS VARCHAR
LANGUAGE SQL
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},"attributes":{"component":"oracle"}}'
EXECUTE AS CALLER
AS
$$
DECLARE
cursor1 CURSOR
FOR
SELECT region_name FROM
hr.regions
WHERE region_id BETWEEN ? AND ?
OR ? < 0;
BEGIN
OPEN cursor1 USING (3, 5, 3);
OPEN cursor1 USING (3, 7, 3);
OPEN cursor1 USING (2, 7, 2);
OPEN cursor1 USING (5, 15, 5);
OPEN cursor1 USING (2, 15, 2);
CLOSE cursor1;
END;
$$;
4.3 Cursores parametrizados com o uso de parâmetros de procedimento na consulta¶
CREATE OR REPLACE PROCEDURE parameterized_cursor_for_sample (high_param number) AS
CURSOR cursor1 (low number DEFAULT 2) IS
SELECT region_name FROM hr.regions
WHERE region_id BETWEEN low AND high_param;
BEGIN
OPEN cursor1(3);
CLOSE cursor1;
END;
CALL parameterized_cursor_for_sample(5);
CREATE OR REPLACE PROCEDURE parameterized_cursor_for_sample (high_param NUMBER(38, 18))
RETURNS VARCHAR
LANGUAGE SQL
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},"attributes":{"component":"oracle"}}'
EXECUTE AS CALLER
AS
$$
DECLARE
cursor1 CURSOR
FOR
SELECT region_name FROM
hr.regions
WHERE region_id BETWEEN ? AND ?;
BEGIN
OPEN cursor1 USING (3, high_param);
CLOSE cursor1;
END;
$$;
CALL parameterized_cursor_for_sample(5);
5. Using Cursors In Fetch And For Loop¶
Os cursores podem ser controlados por meio do uso da instrução FOR, permitindo que cada registro de um cursor seja processado enquanto a instrução FETCH coloca, registro por registro, os valores retornados pelo cursor em um conjunto de variáveis, que podem ser registros PLSQL
5.1 Cursores For Loop¶
CREATE OR REPLACE PROCEDURE p_cursors_for_loop AS
datePlusOne TIMESTAMP;
CURSOR c_product(low number, high number) IS
SELECT name, price, create_on FROM products WHERE price BETWEEN low AND high;
BEGIN
FOR record_product IN c_product(3,5)
LOOP
datePlusOne := record_product.create_on + 1;
INSERT INTO sold_items values(record_product.name, record_product.price, datePlusOne);
END LOOP;
END;
CREATE OR REPLACE PROCEDURE p_cursors_for_loop ()
RETURNS VARCHAR
LANGUAGE SQL
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},"attributes":{"component":"oracle"}}'
EXECUTE AS CALLER
AS
$$
DECLARE
datePlusOne TIMESTAMP(6);
c_product CURSOR
FOR
SELECT
OBJECT_CONSTRUCT('NAME', name, 'PRICE', price, 'CREATE_ON', create_on) sc_cursor_record FROM
products
WHERE price BETWEEN ? AND ?;
BEGIN
OPEN c_product USING (3, 5);
--** SSC-PRF-0004 - THIS STATEMENT HAS USAGES OF CURSOR FOR LOOP **
FOR record_product IN c_product DO
LET record_product OBJECT := record_product.sc_cursor_record;
datePlusOne :=
!!!RESOLVE EWI!!! /*** SSC-EWI-OR0036 - TYPES RESOLUTION ISSUES, ARITHMETIC OPERATION '+' MAY NOT BEHAVE CORRECTLY BETWEEN unknown AND Number ***/!!!
record_product.CREATE_ON + 1;
INSERT INTO sold_items
SELECT
:record_product:NAME,
:record_product:PRICE,
:datePlusOne;
END FOR;
CLOSE c_product;
END;
$$;
5.2 Cursores Fetch¶
CREATE OR REPLACE PROCEDURE p_cursors_fetch AS
record_product products%rowtype;
CURSOR c_product(low number, high number) IS
SELECT * FROM products WHERE price BETWEEN low AND high;
BEGIN
OPEN c_product(3,5);
LOOP
FETCH c_product INTO record_product;
EXIT WHEN c_product%notfound;
INSERT INTO sold_items VALUES (record_product.name, record_product.price);
INSERT INTO sold_items VALUES record_product;
END LOOP;
CLOSE c_product;
END;
CREATE OR REPLACE PROCEDURE p_cursors_fetch ()
RETURNS VARCHAR
LANGUAGE SQL
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},"attributes":{"component":"oracle"}}'
EXECUTE AS CALLER
AS
$$
DECLARE
record_product OBJECT !!!RESOLVE EWI!!! /*** SSC-EWI-0036 - ROWTYPE DATA TYPE CONVERTED TO OBJECT ***/!!! := OBJECT_CONSTRUCT();
c_product CURSOR
FOR
SELECT
OBJECT_CONSTRUCT( *) sc_cursor_record FROM
products
WHERE price BETWEEN ? AND ?;
BEGIN
OPEN c_product USING (3, 5);
LOOP
--** SSC-PRF-0003 - FETCH INSIDE A LOOP IS CONSIDERED A COMPLEX PATTERN, THIS COULD DEGRADE SNOWFLAKE PERFORMANCE. **
FETCH c_product INTO
:record_product;
IF (record_product IS NULL) THEN
EXIT;
END IF;
INSERT INTO sold_items
SELECT
:record_product:NAME,
:record_product:PRICE;
INSERT INTO sold_items
SELECT
null !!!RESOLVE EWI!!! /*** SSC-EWI-OR0002 - COLUMNS FROM EXPRESSION products%rowtype NOT FOUND ***/!!!;
END LOOP;
CLOSE c_product;
END;
$$;
Problemas conhecidos¶
1. RETURN clause is not supported in Snowflake Scripting Cursor Declaration¶
A Declaração de Cursor para Snowflake Scripting não inclui essa cláusula. Ele pode ser removido da definição do Oracle Cursor para obter equivalência funcional.
2. OPEN statement cannot pass values for declared arguments¶
Embora os argumentos possam ser declarados para um cursor, seus valores não podem ser atribuídos no Snowflake Scripting. A melhor alternativa é usar a cláusula USING
com variáveis bind.
3. FETCH statement cannot use records¶
O Snowflake Scripting não oferece suporte a registros. No entanto, é possível migrá-los usando o tipo de dados OBJECT e o método OBJECT_CONSTRUCT(). Para obter mais informações, consulte a seção Definição de tipo de registro.
4. FETCH BULK COLLECT INTO clause is not supported in Snowflake Scripting¶
O Snowflake Scripting não é compatível com a cláusula BULK COLLECT INTO. No entanto, é possível usar ARRAY_AGG junto com uma tabela temporal para construir uma nova variável com os dados correspondentes às informações de Cursor. Para obter mais informações, consulte a seção Operações em massa de coleção.
5. Cursor attributes do not exist in Snowflake Scripting¶
Os cursores Oracle têm diferentes atributos que permitem ao usuário verificar seu status, como se ele está aberto ou a quantidade de linhas obtidas; no entanto, esses atributos referentes ao status do cursor não existem no Snowflake Scripting.
6. The cursor’s query does not have access to the procedure’s variables and parameters¶
No Oracle, a consulta na declaração de cursor tem acesso a variáveis e parâmetros de procedimento, mas no Snowflake Scripting, não. A alternativa a isso é usar a cláusula USING
com variáveis bind. Para obter mais informações, consulte esta seção.
7. %NOTFOUND attribute is not supported in Snowflake Scripting Cursor¶
No Oracle ele pode ser usado, antes da primeira busca de um cursor aberto, cursor_name%NOTFOUND retorna TRUE se a última busca não retornou uma linha, ou FALSE se a última busca retornou uma linha. O Snowflake Scripting não oferece suporte ao uso desse atributo; em vez disso, ele pode ser validado se a variável atribuída ao resultado do cursor contiver valores
EWIs relacionados¶
SSC-EWI-0036: Tipo de dados convertido em outro tipo de dados.
SSC-EWI-OR0002: As colunas da expressão não foram encontradas.
SSC-EWI-OR0036: Problemas de resolução de tipos, a operação aritmética pode não se comportar corretamente entre string e date.
SSC-PRF-0003: A busca dentro de um loop é considerada um padrão complexo, o que pode prejudicar o desempenho do Snowflake.
SSC-PRF-0004: Essa instrução tem usos de cursor para loop.
CURSOR DECLARATION¶
Nota
Instrução não relevante.
Aviso
Observe que essa instrução é removida da migração porque é uma sintaxe não relevante. Isso significa que não é necessária no Snowflake.
Nota
Algumas partes do código de saída foram omitidas por motivos de clareza.
Descrição¶
Esta seção explica a conversão da declaração de cursores no Oracle. Para obter mais informações, consulte a documentação a seguir sobre procedimentos e cursores no Oracle.
Amostra de padrões da origem¶
CURSOR DECLARATION¶
Observe que, neste exemplo, a instrução CURSOR
foi excluída. Essa é uma sintaxe não relevante na transformação direcionada ao Snowflake.
CREATE PROCEDURE PROC_COLLECTIONS
AS
CURSOR C2 RETURN T1%TYPE;
BEGIN
NULL;
END
CREATE OR REPLACE PROCEDURE PROC_COLLECTIONS ()
RETURNS VARCHAR
LANGUAGE SQL
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"oracle"}}'
EXECUTE AS CALLER
AS
$$
BEGIN
NULL;
END;
$$;
Problemas conhecidos ¶
Não foram encontrados problemas.
EWIs Relacionados ¶
Sem EWIs relacionados.
Variáveis de cursor¶
Nota
Algumas partes do código de saída foram omitidas por motivos de clareza.
Descrição¶
Uma variável de cursor é como um cursor explícito que não se limita a uma consulta.
(Declaração de variável de cursor da referência de linguagem Oracle PL/SQL)
Definição do tipo de cursor de referência
TYPE type IS REF CURSOR
[ RETURN
{ {db_table_or_view | cursor | cursor_variable}%ROWTYPE
| record%TYPE
| record_type
| ref_cursor_type
}
] ;
Declaração da variável do cursor
cursor_variable type;
Instrução OPENFOR
OPEN { cursor_variable | :host_cursor_variable}
FOR select_statement [ using_clause ] ;
Aviso
O Snowflake Scripting não tem equivalência direta com as variáveis de cursor e a instrução OPEN FOR
. No entanto, eles podem ser emulados com diferentes soluções alternativas para obter equivalência funcional.
Amostra de padrões da origem¶
1. OPEN FOR statement with dynamic SQL inside a VARCHAR variable¶
CREATE OR REPLACE PROCEDURE procedure1
AS
query1 VARCHAR(200) := 'SELECT 123 FROM dual';
cursor_var SYS_REFCURSOR;
BEGIN
OPEN cursor_var FOR query1;
CLOSE cursor_var;
END;
CREATE OR REPLACE PROCEDURE procedure1 ()
RETURNS VARCHAR
LANGUAGE SQL
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"oracle"}}'
EXECUTE AS CALLER
AS
$$
DECLARE
query1 VARCHAR(200) := 'SELECT 123 FROM dual';
cursor_var_res RESULTSET;
BEGIN
!!!RESOLVE EWI!!! /*** SSC-EWI-0030 - THE STATEMENT BELOW HAS USAGES OF DYNAMIC SQL. ***/!!!
cursor_var_res := (
EXECUTE IMMEDIATE :query1
);
LET cursor_var CURSOR
FOR
cursor_var_res;
OPEN cursor_var;
CLOSE cursor_var;
END;
$$;
2. OPEN FOR statement with dynamic SQL inside a string literal.¶
CREATE OR REPLACE PROCEDURE procedure2
AS
cursor_var SYS_REFCURSOR;
BEGIN
OPEN cursor_var FOR 'SELECT 123 FROM dual';
CLOSE cursor_var;
END;
CREATE OR REPLACE PROCEDURE procedure2 ()
RETURNS VARCHAR
LANGUAGE SQL
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"oracle"}}'
EXECUTE AS CALLER
AS
$$
DECLARE
cursor_var_res RESULTSET;
BEGIN
!!!RESOLVE EWI!!! /*** SSC-EWI-0030 - THE STATEMENT BELOW HAS USAGES OF DYNAMIC SQL. ***/!!!
cursor_var_res := (
EXECUTE IMMEDIATE 'SELECT 123 FROM dual'
);
LET cursor_var CURSOR
FOR
cursor_var_res;
OPEN cursor_var;
CLOSE cursor_var;
END;
$$;
3. OPEN FOR statement with SELECT statement¶
CREATE OR REPLACE PROCEDURE procedure3
AS
cursor_var SYS_REFCURSOR;
BEGIN
OPEN cursor_var FOR SELECT 123 FROM dual;
CLOSE cursor_var;
END;
CREATE OR REPLACE PROCEDURE procedure3 ()
RETURNS VARCHAR
LANGUAGE SQL
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"oracle"}}'
EXECUTE AS CALLER
AS
$$
DECLARE
cursor_var_res RESULTSET;
BEGIN
LET cursor_var CURSOR
FOR
SELECT 123 FROM dual;
OPEN cursor_var;
CLOSE cursor_var;
END;
$$;
4. Cursor Variable declared with REF CURSOR type¶
CREATE OR REPLACE PROCEDURE procedure4
AS
TYPE cursor_ref_type1 IS REF CURSOR;
query1 VARCHAR(200) := 'SELECT 123 FROM dual';
cursor_var cursor_ref_type1;
BEGIN
OPEN cursor_var FOR query1;
CLOSE cursor_var;
END;
CREATE OR REPLACE PROCEDURE procedure4 ()
RETURNS VARCHAR
LANGUAGE SQL
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},"attributes":{"component":"oracle"}}'
EXECUTE AS CALLER
AS
$$
DECLARE
-- !!!RESOLVE EWI!!! /*** SSC-EWI-0058 - FUNCTIONALITY FOR 'PL REF CURSOR TYPE DEFINITION' IS NOT CURRENTLY SUPPORTED BY SNOWFLAKE SCRIPTING ***/!!!
-- TYPE cursor_ref_type1 IS REF CURSOR;
query1 VARCHAR(200) := 'SELECT 123 FROM dual';
cursor_var_res RESULTSET;
BEGIN
!!!RESOLVE EWI!!! /*** SSC-EWI-0030 - THE STATEMENT BELOW HAS USAGES OF DYNAMIC SQL. ***/!!!
cursor_var_res := (
EXECUTE IMMEDIATE :query1
);
LET cursor_var CURSOR
FOR
cursor_var_res;
OPEN cursor_var;
CLOSE cursor_var;
END;
$$;
5. OPEN FOR statement with USING clause¶
CREATE OR REPLACE PROCEDURE procedure5
AS
query1 VARCHAR(200) := 'SELECT col1 FROM cursortable1 WHERE col1 = :a';
column_filter INTEGER := 1;
cursor_var SYS_REFCURSOR;
BEGIN
OPEN cursor_var FOR query1 USING column_filter;
CLOSE cursor_var;
END;
CREATE OR REPLACE PROCEDURE procedure5 ()
RETURNS VARCHAR
LANGUAGE SQL
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"oracle"}}'
EXECUTE AS CALLER
AS
$$
DECLARE
query1 VARCHAR(200) := 'SELECT col1 FROM
cursortable1
WHERE col1 = ?';
column_filter INTEGER := 1;
cursor_var_res RESULTSET;
BEGIN
!!!RESOLVE EWI!!! /*** SSC-EWI-0030 - THE STATEMENT BELOW HAS USAGES OF DYNAMIC SQL. ***/!!!
cursor_var_res := (
EXECUTE IMMEDIATE :query1 USING ( column_filter)
);
LET cursor_var CURSOR
FOR
cursor_var_res;
OPEN cursor_var;
CLOSE cursor_var;
END;
$$;
Problemas conhecidos¶
Não foram encontrados problemas.
EWIs relacionados¶
SSC-EWI-0030: A instrução abaixo tem usos de SQL dinâmico.
SSC-EWI-0058: No momento, a funcionalidade não é compatível com o Snowflake Scripting.
PARAMETRIZED CURSOR¶
Nota
Algumas partes do código de saída foram omitidas por motivos de clareza.
Descrição¶
O Oracle oferece suporte a parâmetros para cursores declarados. No entanto, o Snowflake Scripting não oferece suporte a esse recurso, portanto, a declaração e o uso do cursor não são possíveis.
Exemplo de código¶
Código de entrada Oracle:¶
CREATE OR REPLACE PROCEDURE parametrized_cursor_sample AS
CURSOR cursor1(param1 number) IS SELECT region_name FROM hr.regions where region_id = param1 ORDER BY region_name;
var1 integer;
BEGIN
OPEN cursor1(123);
FETCH cursor1 INTO var1;
CLOSE cursor1;
FOR r1 IN cursor1(456) LOOP
NULL;
END LOOP;
END;
Código de saída:¶
CREATE OR REPLACE PROCEDURE parametrized_cursor_sample ()
RETURNS VARCHAR
LANGUAGE SQL
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},"attributes":{"component":"oracle"}}'
EXECUTE AS CALLER
AS
$$
DECLARE
cursor1 CURSOR
FOR
SELECT
OBJECT_CONSTRUCT('REGION_NAME', region_name) sc_cursor_record FROM
hr.regions
where region_id = ?
ORDER BY region_name;
var1 integer;
BEGIN
OPEN cursor1 USING (123);
FETCH cursor1 INTO
:var1;
CLOSE cursor1;
OPEN cursor1 USING (456);
--** SSC-PRF-0004 - THIS STATEMENT HAS USAGES OF CURSOR FOR LOOP **
FOR r1 IN cursor1 DO
LET r1 OBJECT := r1.sc_cursor_record;
NULL;
END FOR;
CLOSE cursor1;
END;
$$;
Recomendações¶
Tente usar associações para a consulta no cursor e abra o cursor com a cláusula
USING
. Lembre-se de que um parâmetro que é usado várias vezes em um único cursor pode exigir a passagem da variável várias vezes na cláusulaUSING
.
CREATE OR REPLACE PROCEDURE PUBLIC.parametrized_cursor_sample_fixed ()
RETURNS VARCHAR
LANGUAGE SQL
EXECUTE AS CALLER
AS
$$
DECLARE
var1 STRING;
cursor1 CURSOR FOR SELECT region_name FROM hr.regions where region_id = ? ORDER BY region_name;
BEGIN
NULL;
OPEN cursor1 USING (1);
FETCH cursor1 INTO var1;
CLOSE cursor1;
OPEN cursor1 USING (2);
FOR r1 IN cursor1 DO
NULL;
END FOR;
CLOSE cursor1;
END;
$$;
Altere manualmente o cursor para usar as associações.
Se precisar de mais suporte, pode nos enviar um e-mail para snowconvert-support@snowflake.com
EWIs relacionados¶
SSC-PRF-0004: Essa instrução tem usos de cursor para loop.
Solução alternativa para cursores que usam parâmetros ou variáveis de procedimento¶
Descrição¶
Esta seção descreve como simular o uso de parâmetros de cursor e variáveis de procedimento dentro da consulta de um cursor. O nome das variáveis ou parâmetros é substituído por associações usando o sinal ?
. Em seguida, quando o cursor for aberto, os valores deverão ser passados com a cláusula USING
.
Nota
Some parts in the output code are omitted for clarity reasons.
Cursor com variáveis locais¶
Use as vinculações para a consulta no cursor para o parâmetro de variável ou procedimento usado e abra o cursor com a cláusula USING
.
CREATE OR REPLACE PROCEDURE oracle_cursor_sample
AS
like_value VARCHAR(255);
CURSOR c1 IS SELECT region_name FROM hr.regions WHERE region_name LIKE like_value ORDER BY region_name;
r_name VARCHAR(255);
BEGIN
like_value := 'E%';
OPEN c1;
FETCH c1 INTO r_name;
CLOSE c1;
like_value := 'A%';
FOR r1 IN c1 LOOP
NULL;
END LOOP;
END;
CREATE OR REPLACE PROCEDURE oracle_cursor_sample ()
RETURNS VARCHAR
LANGUAGE SQL
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},"attributes":{"component":"oracle"}}'
EXECUTE AS CALLER
AS
$$
DECLARE
like_value VARCHAR(255);
c1 CURSOR
FOR
SELECT region_name FROM
hr.regions
WHERE region_name LIKE ?
ORDER BY region_name;
r_name VARCHAR(255);
BEGIN
like_value := 'E%';
OPEN c1 USING (like_value);
FETCH c1 INTO
:r_name;
CLOSE c1;
like_value := 'A%';
OPEN c1;
--** SSC-PRF-0004 - THIS STATEMENT HAS USAGES OF CURSOR FOR LOOP **
FOR r1 IN c1 DO
NULL;
END FOR;
CLOSE c1;
END;
$$;
Cursor com parâmetros¶
Use associações para a consulta no cursor para cada parâmetro usado e abra o cursor com a cláusula USING
. Lembre-se de que um parâmetro que é usado várias vezes em um único cursor pode exigir a passagem da variável várias vezes na cláusula USING
.
CREATE OR REPLACE PROCEDURE parametrized_cursor_sample AS
CURSOR cursor1(param1 number) IS SELECT region_name FROM hr.regions where region_id = param1 ORDER BY region_name;
var1 integer;
BEGIN
OPEN cursor1(123);
FETCH cursor1 INTO var1;
CLOSE cursor1;
FOR r1 IN cursor1(456) LOOP
NULL;
END LOOP;
END;
CREATE OR REPLACE PROCEDURE parametrized_cursor_sample ()
RETURNS VARCHAR
LANGUAGE SQL
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},"attributes":{"component":"oracle"}}'
EXECUTE AS CALLER
AS
$$
DECLARE
cursor1 CURSOR
FOR
SELECT
OBJECT_CONSTRUCT('REGION_NAME', region_name) sc_cursor_record FROM
hr.regions
where region_id = ?
ORDER BY region_name;
var1 integer;
BEGIN
OPEN cursor1 USING (123);
FETCH cursor1 INTO
:var1;
CLOSE cursor1;
OPEN cursor1 USING (456);
--** SSC-PRF-0004 - THIS STATEMENT HAS USAGES OF CURSOR FOR LOOP **
FOR r1 IN cursor1 DO
LET r1 OBJECT := r1.sc_cursor_record;
NULL;
END FOR;
CLOSE cursor1;
END;
$$;
EWIs relacionados¶
SSC-PRF-0004: Essa instrução tem usos de cursor para loop
CREATE FUNCTION¶
Descrição¶
Nota
Algumas partes do código de saída foram omitidas por motivos de clareza.
Uma função armazenada (também chamada de função de usuário ou função definida pelo usuário) é um conjunto de instruções PL/SQL que você pode chamar pelo nome. As funções armazenadas são muito semelhantes aos procedimentos, exceto pelo fato de que uma função retorna um valor ao ambiente em que é chamada. As funções de usuário podem ser usadas como parte de uma expressão SQL.
Uma especificação de chamada declara um método Java ou uma rotina de linguagem de terceira geração (3GL) para que possa ser chamada a partir de PL/SQL. Você também pode usar a instrução CALL
SQL para chamar esse método ou rotina. A especificação de chamada informa ao Oracle Database qual método Java, ou qual função nomeada em qual biblioteca compartilhada, deve ser invocada quando uma chamada é feita. Ele também informa ao banco de dados quais conversões de tipo devem ser feitas para os argumentos e o valor de retorno. Função Create da referência de linguagem Oracle SQL.
Sintaxe do Oracle¶
Para obter mais informações sobre a função Oracle Create, veja aqui.
CREATE [ OR REPLACE ] [ EDITIONABLE | NONEDITIONABLE ]
FUNCTION
[ schema. ] function_name
[ ( parameter_declaration [, parameter_declaration]... ) ] RETURN datatype
[ sharing_clause ]
[ { invoker_rights_clause
| accessible_by_clause
| default_collation_clause
| deterministic_clause
| parallel_enable_clause
| result_cache_clause
| aggregate_clause
| pipelined_clause
| sql_macro_clause
}...
]
{ IS | AS } { [ declare_section ]
BEGIN statement ...
[ EXCEPTION exception_handler [ exception_handler ]... ]
END [ name ] ;
|
{ java_declaration | c_declaration } } ;
Sintaxe do Snowflake¶
O Snowflake permite 3 idiomas diferentes em suas funções definidas pelo usuário:
SQL
JavaScript
Java
Por enquanto, o SnowConvert será compatível apenas com SQL
e JavaScript
como linguagens de destino.
Para obter mais informações sobre a função Snowflake Create, veja aqui.
Nota
Funções SQL definidas pelo usuário suportam apenas uma consulta como corpo. Elas podem ler do banco de dados, mas não têm permissão para gravar ou modificar (SQL UDFs escalares).
CREATE [ OR REPLACE ] [ SECURE ] FUNCTION <name> ( [ <arg_name> <arg_data_type> ] [ , ... ] )
RETURNS { <result_data_type> | TABLE ( <col_name> <col_data_type> [ , ... ] ) }
[ [ NOT ] NULL ]
[ { CALLED ON NULL INPUT | { RETURNS NULL ON NULL INPUT | STRICT } } ]
[ VOLATILE | IMMUTABLE ]
[ COMMENT = '<string_literal>' ]
AS '<function_definition>'
Nota
Funções JavaScript definidas pelo usuário permitem várias instruções em seus corpos, mas não podem realizar consultas ao banco de dados. (JavaScript UDFs escalares).
CREATE [ OR REPLACE ] [ SECURE ] FUNCTION <name> ( [ <arg_name> <arg_data_type> ] [ , ... ] )
RETURNS { <result_data_type> | TABLE ( <col_name> <col_data_type> [ , ... ] ) }
[ [ NOT ] NULL ]
LANGUAGE JAVASCRIPT
[ { CALLED ON NULL INPUT | { RETURNS NULL ON NULL INPUT | STRICT } } ]
[ VOLATILE | IMMUTABLE ]
[ COMMENT = '<string_literal>' ]
AS '<function_definition>'
Amostra de padrões da origem¶
Amostra de dados auxiliares¶
Nota
Esse código foi executado para uma melhor compreensão dos exemplos:
CREATE TABLE table1 (col1 int, col2 int, col3 varchar2(250), col4 varchar2(250), col5 date);
INSERT INTO table1 VALUES (1, 11, 'val1_1', 'val1_2', TO_DATE('2004/05/03', 'yyyy-MM-dd'));
INSERT INTO table1 VALUES (2, 22, 'val2_1', 'val2_2', TO_DATE('2014/05/03', 'yyyy-MM-dd'));
INSERT INTO table1 VALUES (3, 33, 'val3_1', 'val3_2', TO_DATE('2024/05/03', 'yyyy-MM-dd'));
CREATE OR REPLACE TABLE table1 (col1 int,
col2 int,
col3 VARCHAR(250),
col4 VARCHAR(250),
col5 TIMESTAMP /*** SSC-FDM-OR0042 - DATE TYPE COLUMN HAS A DIFFERENT BEHAVIOR IN SNOWFLAKE. ***/
)
COMMENT = '{ "origin": "sf_sc", "name": "snowconvert", "version": { "major": 0, "minor": 0, "patch": "0" }, "attributes": { "component": "oracle", "convertedOn": "07/25/2024" }}'
;
INSERT INTO table1
VALUES (1, 11, 'val1_1', 'val1_2', TO_DATE('2004/05/03', 'yyyy-MM-dd'));
INSERT INTO table1
VALUES (2, 22, 'val2_1', 'val2_2', TO_DATE('2014/05/03', 'yyyy-MM-dd'));
INSERT INTO table1
VALUES (3, 33, 'val3_1', 'val3_2', TO_DATE('2024/05/03', 'yyyy-MM-dd'));
Problemas conhecidos¶
Não foram encontrados problemas.
EWIS relacionados¶
SSC-FDM-OR0042: O tipo de data transformado em carimbo de data/hora tem um comportamento diferente
Cursor para uma variável de retorno¶
Nota
Algumas partes do código de saída foram omitidas por motivos de clareza.
Esse padrão define uma função no Oracle PL/SQL que usa um cursor para buscar um único valor e retorná-lo.
Componentes:
Declaração de função:
CREATE FUNCTION functionName(parameters) RETURN returnType
Declara a função com os parâmetros de entrada e o tipo de retorno.
Instruções de variáveis:
Declara variáveis, inclusive a variável de retorno.
Declaração de cursor:
CURSOR cursorName IS SELECT singleColumn FROM ... WHERE ... [AND col1 = localVar1];
Define um cursor para selecionar uma única coluna de uma tabela com condições de filtragem opcionais.
Bloco BEGIN-END:
Atribuição de variáveis.
Abre o cursor.
Busca o resultado na variável de retorno.
Fecha o cursor.
Retorna o valor buscado.
Nesse caso, as variáveis são transformadas em uma expressão de tabela comum (CTE). Assim como a consulta dentro do cursor ao qual, além disso, a cláusula FETCH FIRST 1 ROW ONLY
é adicionada para simular o comportamento FETCH CURSOR
.
RETURN
é transformada no select final.
Consultas¶
CREATE OR REPLACE FUNCTION func1 (
company_ IN VARCHAR2,
book_id_ IN DATE,
object_id_ IN VARCHAR2 ) RETURN INTEGER
IS
temp_ table1.col2%TYPE;
CURSOR get_attr IS
SELECT col2
FROM table1
WHERE col3 = company_
AND col4 = object_id_
AND col5 = book_id_;
BEGIN
OPEN get_attr;
FETCH get_attr INTO temp_;
CLOSE get_attr;
RETURN temp_;
END func1;
CREATE OR REPLACE FUNCTION func1 (company_ VARCHAR, book_id_ TIMESTAMP /*** SSC-FDM-OR0042 - DATE TYPE COLUMN HAS A DIFFERENT BEHAVIOR IN SNOWFLAKE. ***/, object_id_ VARCHAR)
RETURNS INTEGER
LANGUAGE SQL
COMMENT = '{ "origin": "sf_sc", "name": "snowconvert", "version": { "major": 0, "minor": 0, "patch": "0" }, "attributes": { "component": "oracle", "convertedOn": "09/06/2024" }}'
AS
$$
WITH declaration_variables_cte1 AS
(
SELECT
(
SELECT col2
FROM table1
WHERE col3 = company_
AND col4 = object_id_
AND col5 = book_id_
FETCH FIRST 1 ROW ONLY) AS temp_
)
SELECT
temp_
FROM
declaration_variables_cte1
$$;
FUNC1() |
-----------------+
2004-05-03. |
CREATE FUNCTION func2 (
fa_period_ IN NUMBER,
to_date_ IN DATE DEFAULT NULL,
from_date_ IN DATE DEFAULT NULL ) RETURN NUMBER
IS
value_ NUMBER;
cond_date_to_ DATE;
cond_date_from_ DATE;
CURSOR get_acq_value IS
SELECT NVL(SUM(col1),0)
FROM table1
WHERE col3 IN (DECODE(fa_period_, 1, 'val1_1', 'val2_1'))
AND col5 <= cond_date_to_
AND col5 >= cond_date_from_;
BEGIN
value_ := 0;
cond_date_to_ := Get_Cond_Date( to_date_, 'MAX' );
cond_date_from_ := Get_Cond_Date( from_date_, 'MIN' );
OPEN get_acq_value;
FETCH get_acq_value INTO value_;
CLOSE get_acq_value;
RETURN (NVL(value_,0));
END func2;
CREATE OR REPLACE FUNCTION func2 (fa_period_ NUMBER(38, 18),
to_date_ TIMESTAMP /*** SSC-FDM-OR0042 - DATE TYPE COLUMN HAS A DIFFERENT BEHAVIOR IN SNOWFLAKE. ***/ DEFAULT NULL,
from_date_ TIMESTAMP /*** SSC-FDM-OR0042 - DATE TYPE COLUMN HAS A DIFFERENT BEHAVIOR IN SNOWFLAKE. ***/ DEFAULT NULL )
RETURNS NUMBER(38, 18)
LANGUAGE SQL
COMMENT = '{ "origin": "sf_sc", "name": "snowconvert", "version": { "major": 0, "minor": 0, "patch": "0" }, "attributes": { "component": "oracle", "convertedOn": "09/06/2024" }}'
AS
$$
WITH declaration_variables_cte1 AS
(
SELECT
0 AS
value_,
Get_Cond_Date( to_date_, 'MAX' ) !!!RESOLVE EWI!!! /*** SSC-EWI-0073 - PENDING FUNCTIONAL EQUIVALENCE REVIEW FOR 'Get_Cond_Date' NODE ***/!!! AS
cond_date_to_,
Get_Cond_Date( from_date_, 'MIN' ) !!!RESOLVE EWI!!! /*** SSC-EWI-0073 - PENDING FUNCTIONAL EQUIVALENCE REVIEW FOR 'Get_Cond_Date' NODE ***/!!! AS
cond_date_from_
),
declaration_variables_cte2 AS
(
SELECT
(
SELECT NVL(SUM(col1),0)
FROM table1
WHERE col3 IN (DECODE(fa_period_, 1, 'val1_1', 'val2_1'))
AND col5 <= cond_date_to_
AND col5 >= cond_date_from_
FETCH FIRST 1 ROW ONLY) AS value_,
cond_date_to_,
cond_date_from_
FROM
declaration_variables_cte1
)
SELECT
(NVL(value_,0))
FROM
declaration_variables_cte2
$$;
FUNC1() |
-----------------+
2004-05-03. |
Problemas conhecidos¶
Não foram encontrados problemas.
EWIS relacionados¶
SSC-FDM-OR0042: O tipo de data transformado em carimbo de data/hora tem um comportamento diferente.
SSC-EWI-0073: Revisão de equivalência funcional pendente.
Cursor com a instrução IF¶
Nota
Algumas partes do código de saída foram omitidas por motivos de clareza.
Esse padrão define uma função que usa condicionalmente um cursor para buscar e retornar um valor com base em uma instrução IF
.
Componentes:
Declaração de função:
CREATE FUNCTION functionName(parameters) RETURN returnType
Declara a função com os parâmetros de entrada e o tipo de retorno.
Declaração de cursor:
CURSOR cursorName IS SELECT singleColumn FROM ... WHERE ... [AND col1 = localVar1];
Define um cursor para selecionar uma única coluna de uma tabela com condições de filtragem opcionais.
Declaração de variáveis:
Declara variáveis, inclusive a variável de retorno.
Bloco BEGIN-END com instrução IF:
Atribuição de variáveis.
Verifique se uma condição é verdadeira.
Se verdadeiro, abre o cursor, busca o resultado na variável de retorno, fecha o cursor e retorna o valor buscado. (O cursor também pode ser aberto no bloco
ELSE
e deve atender às mesmas condições)O bloco
ELSE
é opcional; se existir, deverá conter apenas um único comando que pode ser uma atribuição ou um comandoRETURN
.
As variáveis são transformadas em uma expressão de tabela comum (CTE). Assim como a consulta dentro do cursor ao qual, além disso, a cláusula FETCH FIRST 1 ROW ONLY
é adicionada para simular o comportamento FETCH CURSOR
.
A instrução IF/ELSE
pode ser tratada usando CASE EXPRESSION
dentro de select, permitindo condicionais dentro das consultas. A instrução RETURN
é transformada no select final.
Consultas¶
CREATE OR REPLACE FUNCTION func1 (
company_ IN NUMBER) RETURN NUMBER
IS
CURSOR getmaxperiod IS
SELECT max(col2)
FROM table1;
max_period_ NUMBER := 12;
BEGIN
IF 1 = 1 THEN
OPEN getmaxperiod;
FETCH getmaxperiod INTO max_period_ ;
CLOSE getmaxperiod;
RETURN max_period_;
ELSE
RETURN NULL;
END IF;
END func1;
CREATE OR REPLACE FUNCTION func1 (company_ NUMBER(38, 18))
RETURNS NUMBER(38, 18)
LANGUAGE SQL
COMMENT = '{ "origin": "sf_sc", "name": "snowconvert", "version": { "major": 0, "minor": 0, "patch": "0" }, "attributes": { "component": "oracle", "convertedOn": "09/06/2024" }}'
AS
$$
WITH declaration_variables_cte0 AS
(
SELECT
12 AS
max_period_
),
declaration_variables_cte1 AS
(
SELECT
CASE
WHEN 1 = 1
THEN (
SELECT max(col2)
FROM table1
FETCH FIRST 1 ROW ONLY)
ELSE NULL
END AS max_period_
FROM
declaration_variables_cte0
)
SELECT
max_period_
FROM
declaration_variables_cte1
$$;
FUNC2(0) |
--------------+
NULL |
FUNC2(1) |
--------------+
33 |
CREATE OR REPLACE FUNCTION func2(
company_ IN NUMBER) RETURN NUMBER
IS
CURSOR getmaxperiod IS
SELECT max(col2)
FROM table1;
max_period_ NUMBER := 1;
BEGIN
max_period_:= 2;
IF company_ = 1 THEN
RETURN max_period_ * 2;
ELSE
OPEN getmaxperiod;
FETCH getmaxperiod INTO max_period_ ;
CLOSE getmaxperiod;
RETURN max_period_;
END IF;
END func2;
CREATE OR REPLACE FUNCTION func2 (company_ NUMBER(38, 18))
RETURNS NUMBER(38, 18)
LANGUAGE SQL
COMMENT = '{ "origin": "sf_sc", "name": "snowconvert", "version": { "major": 0, "minor": 0, "patch": "0" }, "attributes": { "component": "oracle", "convertedOn": "09/06/2024" }}'
AS
$$
WITH declaration_variables_cte0 AS
(
SELECT
1 AS
max_period_
),
declaration_variables_cte1 AS
(
SELECT
2 AS
max_period_
FROM
declaration_variables_cte0
),
declaration_variables_cte2 AS
(
SELECT
CASE
WHEN company_ = 1
THEN max_period_ * 2
ELSE (
SELECT max(col2)
FROM table1
FETCH FIRST 1 ROW ONLY)
END AS max_period_
FROM
declaration_variables_cte1
)
SELECT
max_period_
FROM
declaration_variables_cte2
$$;
FUNC2(0) |
--------------+
33 |
FUNC2(1) |
--------------+
2 |
CREATE OR REPLACE FUNCTION func3 (
company_ IN NUMBER) RETURN NUMBER
IS
CURSOR getmaxperiod IS
SELECT max(col2)
FROM table1;
max_period_ NUMBER := 0;
BEGIN
IF company_ = 1 THEN
OPEN getmaxperiod;
FETCH getmaxperiod INTO max_period_ ;
CLOSE getmaxperiod;
END IF;
RETURN max_period_;
END func10;
CREATE OR REPLACE FUNCTION func3 (company_ NUMBER(38, 18))
RETURNS NUMBER(38, 18)
LANGUAGE SQL
COMMENT = '{ "origin": "sf_sc", "name": "snowconvert", "version": { "major": 0, "minor": 0, "patch": "0" }, "attributes": { "component": "oracle", "convertedOn": "09/06/2024" }}'
AS
$$
WITH declaration_variables_cte0 AS
(
SELECT
0 AS
max_period_
),
declaration_variables_cte1 AS
(
SELECT
CASE
WHEN company_ = 1
THEN (
SELECT max(col2)
FROM table1
FETCH FIRST 1 ROW ONLY)
ELSE max_period_
END AS max_period_
FROM
declaration_variables_cte0
)
SELECT
max_period_
FROM
declaration_variables_cte1
$$;
FUNC2(0) |
--------------+
0 |
FUNC2(1) |
--------------+
33 |
Problemas conhecidos¶
Não foram encontrados problemas.
EWIS relacionados¶
Sem EWIs relacionados
Instrução com múltiplos IFs¶
Esse padrão define uma função que usa instruções condicionais sobre variáveis locais.
Componentes:
Declaração de função:
CREATE FUNCTION functionName(parameters) RETURN returnType
Declara a função com os parâmetros de entrada e o tipo de retorno.
Declaração de variáveis:
Declara variáveis, inclusive a variável de retorno.
Bloco BEGIN-END com instrução IF:
Verifique se uma condição é verdadeira.
Cada caso é usado para atribuir um valor à mesma variável.
Conversão:¶
DECLARE SECTION
: variáveis com uma expressão padrão são movidas para uma expressão de tabela comum.
A instrução IF/ELSE
pode ser tratada usando CASE EXPRESSION
dentro de select, permitindo condicionais dentro das consultas.
RETURN
é transformada no select final.
CREATE OR REPLACE FUNCTION Case1 (
in_date_ IN DATE,
min_max_ IN VARCHAR2 )
RETURN DATE
IS
cond_date_ DATE := CURRENT_DATE;
BEGIN
IF ( in_date_ IS NULL ) THEN
IF ( min_max_ = 'MIN' ) THEN
cond_date_ := FOO1();
ELSE
cond_date_ := FOO2();
END IF;
ELSE
cond_date_ := TRUNC(in_date_);
END IF;
RETURN cond_date_;
END Case1;
CREATE OR REPLACE FUNCTION Case1 (in_date_ TIMESTAMP /*** SSC-FDM-OR0042 - DATE TYPE COLUMN HAS A DIFFERENT BEHAVIOR IN SNOWFLAKE. ***/, min_max_ VARCHAR)
RETURNS TIMESTAMP /*** SSC-FDM-OR0042 - DATE TYPE COLUMN HAS A DIFFERENT BEHAVIOR IN SNOWFLAKE. ***/
LANGUAGE SQL
COMMENT = '{ "origin": "sf_sc", "name": "snowconvert", "version": { "major": 0, "minor": 0, "patch": "0" }, "attributes": { "component": "oracle", "convertedOn": "09/06/2024" }}'
AS
$$
WITH declaration_variables_cte0 AS
(
SELECT
CURRENT_DATE AS
cond_date_
),
declaration_variables_cte1 AS
(
SELECT
CASE
WHEN ( in_date_ IS NULL )
THEN CASE
WHEN ( min_max_ = 'MIN' )
THEN FOO1() !!!RESOLVE EWI!!! /*** SSC-EWI-0073 - PENDING FUNCTIONAL EQUIVALENCE REVIEW FOR 'FOO1' NODE ***/!!!
ELSE FOO2() !!!RESOLVE EWI!!! /*** SSC-EWI-0073 - PENDING FUNCTIONAL EQUIVALENCE REVIEW FOR 'FOO2' NODE ***/!!!
END
ELSE TRUNC(in_date_, 'DD')
END AS cond_date_
FROM
declaration_variables_cte0
)
SELECT
cond_date_
FROM
declaration_variables_cte1
$$;
CREATE OR REPLACE FUNCTION Case2 (
year_ IN NUMBER,
id IN NUMBER)
RETURN VARCHAR2
IS
base_value_ NUMBER;
fully_depritiated_ VARCHAR2(5);
residual_value_ NUMBER;
acc_depr_prev_ NUMBER;
acc_depr_ NUMBER;
BEGIN
base_value_ := FOO1(year_, id);
acc_depr_ := FOO2(year_, id);
acc_depr_prev_ := FOO3(year_, id);
residual_value_ := NVL(base_value_,0) -(acc_depr_ + acc_depr_prev_);
IF (residual_value_=0 AND base_value_!=0) THEN
fully_depritiated_ := 'TRUE';
ELSE
fully_depritiated_ := 'FALSE';
END IF;
RETURN fully_depritiated_;
END Case2;
CREATE OR REPLACE FUNCTION Case2 (year_ NUMBER(38, 18), id NUMBER(38, 18))
RETURNS VARCHAR
LANGUAGE SQL
COMMENT = '{ "origin": "sf_sc", "name": "snowconvert", "version": { "major": 0, "minor": 0, "patch": "0" }, "attributes": { "component": "oracle", "convertedOn": "09/06/2024" }}'
AS
$$
WITH declaration_variables_cte1 AS
(
SELECT
FOO1(year_, id) !!!RESOLVE EWI!!! /*** SSC-EWI-0073 - PENDING FUNCTIONAL EQUIVALENCE REVIEW FOR 'FOO1' NODE ***/!!! AS
base_value_,
FOO2(year_, id) !!!RESOLVE EWI!!! /*** SSC-EWI-0073 - PENDING FUNCTIONAL EQUIVALENCE REVIEW FOR 'FOO2' NODE ***/!!! AS
acc_depr_,
FOO3(year_, id) !!!RESOLVE EWI!!! /*** SSC-EWI-0073 - PENDING FUNCTIONAL EQUIVALENCE REVIEW FOR 'FOO3' NODE ***/!!! AS
acc_depr_prev_,
!!!RESOLVE EWI!!! /*** SSC-EWI-OR0036 - TYPES RESOLUTION ISSUES, ARITHMETIC OPERATION '-' MAY NOT BEHAVE CORRECTLY BETWEEN ExactNumeric AND unknown ***/!!!
NVL(base_value_,0) -(acc_depr_ + acc_depr_prev_) AS
residual_value_,
CASE
WHEN (residual_value_=0 AND base_value_!=0)
THEN 'TRUE'
ELSE 'FALSE'
END AS fully_depritiated_
)
SELECT
fully_depritiated_
FROM
declaration_variables_cte1
$$;
CREATE OR REPLACE FUNCTION Case2_1 (
year_ IN NUMBER,
id IN NUMBER)
RETURN VARCHAR2
IS
base_value_ NUMBER;
fully_depritiated_ VARCHAR2(5);
residual_value_ NUMBER;
acc_depr_prev_ NUMBER;
acc_depr_ NUMBER;
BEGIN
base_value_ := FOO1(year_, id);
acc_depr_ := FOO2(year_, id);
acc_depr_prev_ := FOO3(year_, id);
residual_value_ := NVL(base_value_,0) -(acc_depr_ + acc_depr_prev_);
IF (residual_value_=0 AND base_value_!=0) THEN
fully_depritiated_ := 'TRUE';
ELSE
fully_depritiated_ := 'FALSE';
END IF;
fully_depritiated := fully_depritiated || ' CONCAT FOR TESTING';
fully_depritiated := fully_depritiated || ' CONCAT FOR TESTING2';
RETURN fully_depritiated_;
END Case2;
CREATE OR REPLACE FUNCTION Case2_1 (year_ NUMBER(38, 18), id NUMBER(38, 18))
RETURNS VARCHAR
LANGUAGE SQL
COMMENT = '{ "origin": "sf_sc", "name": "snowconvert", "version": { "major": 0, "minor": 0, "patch": "0" }, "attributes": { "component": "oracle", "convertedOn": "09/06/2024" }}'
AS
$$
WITH declaration_variables_cte1 AS
(
SELECT
FOO1(year_, id) !!!RESOLVE EWI!!! /*** SSC-EWI-0073 - PENDING FUNCTIONAL EQUIVALENCE REVIEW FOR 'FOO1' NODE ***/!!! AS
base_value_,
FOO2(year_, id) !!!RESOLVE EWI!!! /*** SSC-EWI-0073 - PENDING FUNCTIONAL EQUIVALENCE REVIEW FOR 'FOO2' NODE ***/!!! AS
acc_depr_,
FOO3(year_, id) !!!RESOLVE EWI!!! /*** SSC-EWI-0073 - PENDING FUNCTIONAL EQUIVALENCE REVIEW FOR 'FOO3' NODE ***/!!! AS
acc_depr_prev_,
!!!RESOLVE EWI!!! /*** SSC-EWI-OR0036 - TYPES RESOLUTION ISSUES, ARITHMETIC OPERATION '-' MAY NOT BEHAVE CORRECTLY BETWEEN ExactNumeric AND unknown ***/!!!
NVL(base_value_,0) -(acc_depr_ + acc_depr_prev_) AS
residual_value_,
CASE
WHEN (residual_value_=0 AND base_value_!=0)
THEN 'TRUE'
ELSE 'FALSE'
END AS fully_depritiated_,
NVL(fully_depritiated :: STRING, '') || ' CONCAT FOR TESTING' AS
fully_depritiated
),
declaration_variables_cte2 AS
(
SELECT
NVL(fully_depritiated :: STRING, '') || ' CONCAT FOR TESTING2' AS
fully_depritiated,
base_value_,
acc_depr_,
acc_depr_prev_,
residual_value_
FROM
declaration_variables_cte1
)
SELECT
fully_depritiated_
FROM
declaration_variables_cte2
$$;
CREATE OR REPLACE FUNCTION Case2_1 (
year_ IN NUMBER,
id IN NUMBER)
RETURN VARCHAR2
IS
base_value_ NUMBER;
fully_depritiated_ VARCHAR2(5);
residual_value_ NUMBER;
acc_depr_prev_ NUMBER;
acc_depr_ NUMBER;
BEGIN
base_value_ := FOO1(year_, id);
acc_depr_ := FOO2(year_, id);
acc_depr_prev_ := FOO3(year_, id);
residual_value_ := NVL(base_value_,0) -(acc_depr_ + acc_depr_prev_);
IF (residual_value_=0 AND base_value_!=0) THEN
fully_depritiated_ := 'TRUE';
ELSE
fully_depritiated_ := 'FALSE';
END IF;
fully_depritiated := fully_depritiated || ' CONCAT FOR TESTING';
fully_depritiated := fully_depritiated || ' CONCAT FOR TESTING2';
RETURN fully_depritiated_;
END Case2;
CREATE OR REPLACE FUNCTION Case2_1 (year_ NUMBER(38, 18), id NUMBER(38, 18))
RETURNS VARCHAR
LANGUAGE SQL
COMMENT = '{ "origin": "sf_sc", "name": "snowconvert", "version": { "major": 0, "minor": 0, "patch": "0" }, "attributes": { "component": "oracle", "convertedOn": "09/06/2024" }}'
AS
$$
WITH declaration_variables_cte1 AS
(
SELECT
FOO1(year_, id) !!!RESOLVE EWI!!! /*** SSC-EWI-0073 - PENDING FUNCTIONAL EQUIVALENCE REVIEW FOR 'FOO1' NODE ***/!!! AS
base_value_,
FOO2(year_, id) !!!RESOLVE EWI!!! /*** SSC-EWI-0073 - PENDING FUNCTIONAL EQUIVALENCE REVIEW FOR 'FOO2' NODE ***/!!! AS
acc_depr_,
FOO3(year_, id) !!!RESOLVE EWI!!! /*** SSC-EWI-0073 - PENDING FUNCTIONAL EQUIVALENCE REVIEW FOR 'FOO3' NODE ***/!!! AS
acc_depr_prev_,
!!!RESOLVE EWI!!! /*** SSC-EWI-OR0036 - TYPES RESOLUTION ISSUES, ARITHMETIC OPERATION '-' MAY NOT BEHAVE CORRECTLY BETWEEN ExactNumeric AND unknown ***/!!!
NVL(base_value_,0) -(acc_depr_ + acc_depr_prev_) AS
residual_value_,
CASE
WHEN (residual_value_=0 AND base_value_!=0)
THEN 'TRUE'
ELSE 'FALSE'
END AS fully_depritiated_,
NVL(fully_depritiated :: STRING, '') || ' CONCAT FOR TESTING' AS
fully_depritiated
),
declaration_variables_cte2 AS
(
SELECT
NVL(fully_depritiated :: STRING, '') || ' CONCAT FOR TESTING2' AS
fully_depritiated,
base_value_,
acc_depr_,
acc_depr_prev_,
residual_value_
FROM
declaration_variables_cte1
)
SELECT
fully_depritiated_
FROM
declaration_variables_cte2
$$;
Problemas conhecidos¶
Não foram encontrados problemas.
EWIS relacionados¶
SSC-FDM-OR0042: O tipo de data transformado em carimbo de data/hora tem um comportamento diferente.
SSC-EWI-0073: Revisão de equivalência funcional pendente.
SSC-EWI-OR0036: Problemas de resolução de tipos, a operação aritmética pode não se comportar corretamente entre string e date.
DML STATEMENTS¶
Descrição ¶
As extensões de instrução DML diferem das instruções DML normais porque podem usar elementos de PL/SQL como coleções e registros. Até o momento, alguns desses elementos não são compatíveis com o Snowflake Scripting. Se uma instrução não for suportada, um EWI será adicionado durante a conversão. Outras instruções DML serão convertidos como se não estivessem dentro de um procedimento.
As instruções a seguir são consideradas DML:
Há uma seção que descreve como simular o comportamento de RECORDS e COLLECTIONS para as instruções SELECT e INSERT:
Extensão da instrução INSERT¶
Nota
Algumas partes do código de saída foram omitidas por motivos de clareza.
Descrição¶
A extensão PL/SQL da instrução SQL INSERT
permite especificar um nome de registro na values_clause
da single_table_insert
em vez de especificar uma lista de colunas na insert_into_clause.
(Extensão da instrução INSERT da referência de linguagem Oracle PL/SQL)
O Snowflake INSERT INTO difere do Snowflake Scripting nas restrições de variáveis; é necessário que os nomes sejam precedidos por dois pontos «:» para vincular o valor das variáveis.
Recomendações¶
Nota
Esse código foi executado para uma melhor compreensão dos exemplos:
CREATE TABLE numbers_table(num integer, word varchar2(20));
CREATE OR REPLACE TABLE PUBLIC.numbers_table (num integer,
word VARCHAR(20));
Extensão da instrução INSERT de caso simples¶
Oracle¶
CREATE OR REPLACE PROCEDURE proc_insert_statement
AS
number_variable integer := 10;
word_variable varchar2(20) := 'ten';
BEGIN
INSERT INTO numbers_table VALUES(number_variable, word_variable);
INSERT INTO numbers_table VALUES(11, 'eleven');
END;
CALL proc_insert_statement();
SELECT * FROM numbers_table ;
|NUM|WORD |
|---|------|
|10 |ten |
|11 |eleven|
Script Snowflake¶
CREATE OR REPLACE PROCEDURE proc_insert_statement ()
RETURNS VARCHAR
LANGUAGE SQL
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"oracle"}}'
EXECUTE AS CALLER
AS
$$
DECLARE
number_variable integer := 10;
word_variable VARCHAR(20) := 'ten';
BEGIN
INSERT INTO numbers_table
VALUES(:number_variable, :word_variable);
INSERT INTO numbers_table
VALUES(11, 'eleven');
END;
$$;
CALL proc_insert_statement();
SELECT * FROM
numbers_table;
|NUM|WORD |
|---|------|
|10 |ten |
|11 |eleven|
Problemas conhecidos¶
1. Records are not supported by Snowflake Scripting¶
Como os registros não são compatíveis com o Snowflake Scripting, em vez de usar a cláusula VALUES record
, é necessário transformá-la em uma cláusula SELECT e dividir as colunas do registro. Para obter mais informações, consulte a seção Definição de tipo de registro.
EWIs relacionados¶
Sem EWIs relacionados.
Instrução MERGE¶
Nota
Algumas partes do código de saída foram omitidas por motivos de clareza.
Descrição¶
A instrução MERGE
é usada para selecionar linhas de uma ou mais fontes para atualização ou inserção em uma tabela ou visualização. É possível especificar condições para determinar se você deve atualizar ou inserir na tabela ou visualização de destino. Essa instrução é uma maneira conveniente de combinar várias operações. Isso permite evitar várias instruções INSERT
, UPDATE
e DELETE
DML. MERGE
é uma instrução determinística. Não é possível atualizar a mesma linha da tabela de destino várias vezes na mesma instrução MERGE
. (Instrução MERGE da referência de linguagem Oracle PL/SQL))
MERGE [ hint ]
INTO [ schema. ] { table | view } [ t_alias ]
USING { [ schema. ] { table | view }
| ( subquery )
} [ t_alias ]
ON ( condition )
[ merge_update_clause ]
[ merge_insert_clause ]
[ error_logging_clause ] ;
merge_update_clause := WHEN MATCHED THEN
UPDATE SET column = { expr | DEFAULT }
[, column = { expr | DEFAULT } ]...
[ where_clause ]
[ DELETE where_clause ]
merge_insert_clause := WHEN NOT MATCHED THEN
INSERT [ (column [, column ]...) ]
VALUES ({ expr | DEFAULT }
[, { expr | DEFAULT } ]...
)
[ where_clause ]
error_logging_clause := LOG ERRORS
[ INTO [schema.] table ]
[ (simple_expression) ]
[ REJECT LIMIT { integer | UNLIMITED } ]
where_clause := WHERE condition
MERGE INTO <target_table> USING <source> ON <join_expr>
{ matchedClause | notMatchedClause } [ ... ]
matchedClause ::= WHEN MATCHED [ AND <case_predicate> ]
THEN { UPDATE SET <col_name> = <expr> [ , <col_name2> = <expr2> ... ] | DELETE } [ ... ]
notMatchedClause ::= WHEN NOT MATCHED [ AND <case_predicate> ]
THEN INSERT [ ( <col_name> [ , ... ] ) ] VALUES ( <expr> [ , ... ] )
Amostra de padrões da origem¶
Amostra de dados auxiliares¶
Nota
Esse código foi executado para uma melhor compreensão dos exemplos:
CREATE TABLE people_source (
person_id INTEGER NOT NULL PRIMARY KEY,
first_name VARCHAR2(20) NOT NULL,
last_name VARCHAR2(20) NOT NULL,
title VARCHAR2(10) NOT NULL
);
CREATE TABLE people_target (
person_id INTEGER NOT NULL PRIMARY KEY,
first_name VARCHAR2(20) NOT NULL,
last_name VARCHAR2(20) NOT NULL,
title VARCHAR2(10) NOT NULL
);
CREATE TABLE bonuses (
employee_id NUMBER,
bonus NUMBER DEFAULT 100
);
INSERT INTO people_target
VALUES (1, 'John', 'Smith', 'Mr');
INSERT INTO people_target
VALUES (2, 'alice', 'jones', 'Mrs');
INSERT INTO people_source
VALUES (2, 'Alice', 'Jones', 'Mrs.');
INSERT INTO people_source
VALUES (3, 'Jane', 'Doe', 'Miss');
INSERT INTO people_source
VALUES (4, 'Dave', 'Brown', 'Mr');
INSERT INTO
bonuses(employee_id) (
SELECT
e.employee_id
FROM
hr.employees e,
oe.orders o
WHERE
e.employee_id = o.sales_rep_id
GROUP BY
e.employee_id
);
CREATE OR REPLACE TABLE people_source (
person_id INTEGER NOT NULL PRIMARY KEY,
first_name VARCHAR(20) NOT NULL,
last_name VARCHAR(20) NOT NULL,
title VARCHAR(10) NOT NULL
)
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"oracle"}}'
;
CREATE OR REPLACE TABLE people_target (
person_id INTEGER NOT NULL PRIMARY KEY,
first_name VARCHAR(20) NOT NULL,
last_name VARCHAR(20) NOT NULL,
title VARCHAR(10) NOT NULL
)
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"oracle"}}'
;
CREATE OR REPLACE TABLE bonuses (
employee_id NUMBER(38, 18) /*** SSC-FDM-0006 - NUMBER TYPE COLUMN MAY NOT BEHAVE SIMILARLY IN SNOWFLAKE. ***/,
bonus NUMBER(38, 18) /*** SSC-FDM-0006 - NUMBER TYPE COLUMN MAY NOT BEHAVE SIMILARLY IN SNOWFLAKE. ***/ DEFAULT 100
)
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"oracle"}}'
;
INSERT INTO people_target
VALUES (1, 'John', 'Smith', 'Mr');
INSERT INTO people_target
VALUES (2, 'alice', 'jones', 'Mrs');
INSERT INTO people_source
VALUES (2, 'Alice', 'Jones', 'Mrs.');
INSERT INTO people_source
VALUES (3, 'Jane', 'Doe', 'Miss');
INSERT INTO people_source
VALUES (4, 'Dave', 'Brown', 'Mr');
INSERT INTO bonuses(employee_id) (
SELECT
e.employee_id
FROM
hr.employees e,
oe.orders o
WHERE
e.employee_id = o.sales_rep_id
GROUP BY
e.employee_id
);
Caso simples da instrução MERGE¶
Oracle¶
MERGE INTO people_target pt USING people_source ps ON (pt.person_id = ps.person_id)
WHEN MATCHED THEN
UPDATE
SET
pt.first_name = ps.first_name,
pt.last_name = ps.last_name,
pt.title = ps.title
WHEN NOT MATCHED THEN
INSERT
(
pt.person_id,
pt.first_name,
pt.last_name,
pt.title
)
VALUES
(
ps.person_id,
ps.first_name,
ps.last_name,
ps.title
);
SELECT * FROM people_target;
PERSON_ID|FIRST_NAME|LAST_NAME|TITLE|
---------+----------+---------+-----+
1|John |Smith |Mr |
2|Alice |Jones |Mrs. |
3|Jane |Doe |Miss |
4|Dave |Brown |Mr |
Snowflake¶
MERGE INTO people_target pt USING people_source ps ON (pt.person_id = ps.person_id)
WHEN MATCHED THEN
UPDATE
SET
pt.first_name = ps.first_name,
pt.last_name = ps.last_name,
pt.title = ps.title
WHEN NOT MATCHED THEN
INSERT
(
pt.person_id,
pt.first_name,
pt.last_name,
pt.title
)
VALUES
(
ps.person_id,
ps.first_name,
ps.last_name,
ps.title
);
SELECT * FROM
people_target;
PERSON_ID|FIRST_NAME|LAST_NAME|TITLE|
---------+----------+---------+-----+
1|John |Smith |Mr |
2|Alice |Jones |Mrs. |
3|Jane |Doe |Miss |
4|Dave |Brown |Mr |
Instrução MERGE com DELETE e cláusula where¶
Para encontrar uma equivalência entre a instrução DELETE e a cláusula where, é necessário reordenar e implementar algumas alterações na instrução de mesclagem do Snowflake.
Alterações necessárias:¶
Substitua DELETE where_clause do Oracle por uma nova matchedClause do Snowflake com a instrução AND predicate
Substitua where_clause de merge_insert_clause do Oracle por uma instrução AND predicate no Snowflake notMatchedClause
Oracle¶
MERGE INTO bonuses D USING (
SELECT
employee_id,
salary,
department_id
FROM
hr.employees
WHERE
department_id = 80
) S ON (D.employee_id = S.employee_id)
WHEN MATCHED THEN
UPDATE
SET
D.bonus = D.bonus + S.salary *.01 DELETE
WHERE
(S.salary > 8000)
WHEN NOT MATCHED THEN
INSERT
(D.employee_id, D.bonus)
VALUES
(S.employee_id, S.salary *.01)
WHERE
(S.salary <= 8000);
SELECT * FROM bonuses ORDER BY employee_id;
EMPLOYEE_ID|BONUS|
-----------+-----+
153| 180|
154| 175|
155| 170|
159| 180|
160| 175|
161| 170|
164| 72|
165| 68|
166| 64|
167| 62|
171| 74|
172| 73|
173| 61|
179| 62|
Snowflake¶
--** SSC-FDM-OR0018 - SNOWFLAKE MERGE STATEMENT MAY HAVE SOME FUNCTIONAL DIFFERENCES COMPARED TO ORACLE **
MERGE INTO bonuses D USING (
SELECT
employee_id,
salary,
department_id
FROM
hr.employees
WHERE
department_id = 80) S ON (D.employee_id = S.employee_id)
WHEN MATCHED AND
(S.salary > 8000) THEN
DELETE
WHEN MATCHED THEN
UPDATE SET
D.bonus = D.bonus + S.salary *.01
WHEN NOT MATCHED AND
(S.salary <= 8000) THEN
INSERT
(D.employee_id, D.bonus)
VALUES
(S.employee_id, S.salary *.01);
SELECT * FROM
bonuses
ORDER BY employee_id;
EMPLOYEE_ID|BONUS|
-----------+-----+
153| 180|
154| 175|
155| 170|
159| 180|
160| 175|
161| 170|
164| 72|
165| 68|
166| 64|
167| 62|
171| 74|
172| 73|
173| 61|
179| 62|
Aviso
Em alguns casos, as alterações aplicadas podem não funcionar como esperado, como no exemplo a seguir:
Oracle¶
MERGE INTO people_target pt USING people_source ps ON (pt.person_id = ps.person_id)
WHEN MATCHED THEN
UPDATE
SET
pt.first_name = ps.first_name,
pt.last_name = ps.last_name,
pt.title = ps.title DELETE
where
pt.title = 'Mrs.'
WHEN NOT MATCHED THEN
INSERT
(
pt.person_id,
pt.first_name,
pt.last_name,
pt.title
)
VALUES
(
ps.person_id,
ps.first_name,
ps.last_name,
ps.title
)
WHERE
ps.title = 'Mr';
SELECT * FROM people_target;
PERSON_ID|FIRST_NAME|LAST_NAME|TITLE|
---------+----------+---------+-----+
1|John |Smith |Mr |
4|Dave |Brown |Mr |
Snowflake¶
--** SSC-FDM-OR0018 - SNOWFLAKE MERGE STATEMENT MAY HAVE SOME FUNCTIONAL DIFFERENCES COMPARED TO ORACLE **
MERGE INTO people_target pt USING people_source ps ON (pt.person_id = ps.person_id)
WHEN MATCHED AND
pt.title = 'Mrs.' THEN
DELETE
WHEN MATCHED THEN
UPDATE SET
pt.first_name = ps.first_name,
pt.last_name = ps.last_name,
pt.title = ps.title
WHEN NOT MATCHED AND
ps.title = 'Mr' THEN
INSERT
(
pt.person_id,
pt.first_name,
pt.last_name,
pt.title
)
VALUES
(
ps.person_id,
ps.first_name,
ps.last_name,
ps.title
);
SELECT * FROM
people_target;
PERSON_ID|FIRST_NAME|LAST_NAME|TITLE|
---------+----------+---------+-----+
1|John |Smith |Mr |
2|Alice |Jones |Mrs. |
4|Dave |Brown |Mr |
Problemas conhecidos¶
1. Oracle’s error_logging_clause is not supported¶
Não há equivalente para a cláusula de registro de erros no Snowflake Scripting.
2. Changed applied do not work as expected¶
Às vezes, as alterações aplicadas para obter a equivalência funcional entre a instrução de mesclagem do Oracle e do Snowflake não funcionam como esperado.
EWIs relacionados¶
SSC-FDM-0006: A coluna de tipo de número pode não se comportar de forma semelhante no Snowflake.
SSC-FDM-OR0018: A instrução de mesclagem pode não funcionar como esperado
Instrução SELECTINTO¶
Nota
Algumas partes do código de saída foram omitidas por motivos de clareza.
Descrição¶
A instrução SELECT
INTO
recupera valores de uma ou mais tabelas do banco de dados (como faz a instrução SQL SELECT
) e os armazena em variáveis (o que não é feito pela instrução SQL SELECT
). (Instrução SELECT INTO da referência de linguagem Oracle PL/SQL)
SELECT [ { DISTINCT | UNIQUE } | ALL ] select_list
{ into_clause | bulk_collect_into_clause } FROM rest-of-statement ;
INTO { variable [, variable ]... | record )
BULK COLLECT INTO { collection | :host_array }
[, { collection | :host_array } ]...
SELECT [ { ALL | DISTINCT } ]
{
[{<object_name>|<alias>}.]*
| [{<object_name>|<alias>}.]<col_name>
| [{<object_name>|<alias>}.]$<col_position>
| <expr>
[ [ AS ] <col_alias> ]
}
[ , ... ]
INTO :<variable> [, :<variable> ... ]
[...]
Amostra de padrões da origem¶
Amostra de dados auxiliares¶
Nota
Esse código foi executado para uma melhor compreensão dos exemplos:
CREATE TABLE numbers_table(num integer, word varchar2(20));
INSERT INTO numbers_table VALUES (1, 'one');
CREATE TABLE aux_numbers_table(aux_num integer, aux_word varchar2(20));
CREATE OR REPLACE TABLE numbers_table (num integer,
word VARCHAR(20))
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"oracle"}}'
;
INSERT INTO numbers_table
VALUES (1, 'one');
CREATE OR REPLACE TABLE aux_numbers_table (aux_num integer,
aux_word VARCHAR(20))
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"oracle"}}'
;
Caso simples da instrução SELECTINTO¶
Oracle¶
CREATE OR REPLACE PROCEDURE proc_select_into_variables
AS
number_variable integer;
word_variable varchar2(20);
BEGIN
SELECT * INTO number_variable, word_variable FROM numbers_table;
INSERT INTO aux_numbers_table VALUES(number_variable, word_variable);
END;
CALL proc_select_into_variables();
SELECT * FROM aux_numbers_table;
|AUX_NUM|AUX_WORD|
|-------|--------|
|1 |one |
Script Snowflake¶
CREATE OR REPLACE PROCEDURE proc_select_into_variables ()
RETURNS VARCHAR
LANGUAGE SQL
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"oracle"}}'
EXECUTE AS CALLER
AS
$$
DECLARE
number_variable integer;
word_variable VARCHAR(20);
BEGIN
SELECT * INTO
:number_variable,
:word_variable
FROM
numbers_table;
INSERT INTO aux_numbers_table
VALUES(:number_variable, :word_variable);
END;
$$;
CALL proc_select_into_variables();
SELECT * FROM
aux_numbers_table;
|AUX_NUM|AUX_WORD|
|-------|--------|
|1 |one |
Problemas conhecidos¶
1. BULK COLLECT INTO is not supported¶
O Snowflake Scripting não é compatível com a cláusula BULK COLLECT INTO. No entanto, é possível usar ARRAY_AGG para construir uma nova variável. Para obter mais informações, consulte a seção Operações em massa de coleção.
2. Collections and records are not supported¶
O Snowflake Scripting não suporta o uso de coleções nem de registros. É possível migrá-los usando tipos de dados semiestruturados, conforme explicado nesta seção.
EWIs relacionados¶
Sem EWIs relacionados.
Solução alternativa para simular o uso de registros¶
Aviso
Esta página está obsoleta, mas foi deixada para fins de compatibilidade. Se quiser ver a seção atualizada, consulte Coleções e registros
Descrição¶
Esta seção descreve como simular o comportamento dos registros Oracle em instruções SELECT e INSERT, usando RESULTSET e CURSORS do Snowflake Scripting.
Snowflake Scripting RESULTSET e CURSOR¶
<resultset_name> RESULTSET [ DEFAULT ( <query> ) ] ;
LET <resultset_name> RESULTSET [ { DEFAULT | := } ( <query> ) ] ;
LET <resultset_name> RESULTSET [ { DEFAULT | := } ( <query> ) ] ;
Recomendações¶
Nota
Nos exemplos a seguir, esse código foi executado para melhor compreensão dos exemplos:
CREATE TABLE numbers_table(num integer, word varchar2(20));
INSERT INTO numbers_table VALUES (1, 'one');
CREATE TABLE aux_numbers_table(aux_num integer, aux_word varchar2(20));
CREATE OR REPLACE TABLE numbers_table (num integer,
word VARCHAR(20))
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"oracle"}}'
;
INSERT INTO numbers_table
VALUES (1, 'one');
CREATE OR REPLACE TABLE aux_numbers_table (aux_num integer,
aux_word VARCHAR(20))
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"oracle"}}'
;
Usando RESULTSET e Cursores em vez de Registros¶
Oracle¶
CREATE OR REPLACE PROCEDURE proc_insert_select_resultset
AS
TYPE number_record_definition IS RECORD(
rec_num numbers_table.num%type,
rec_word numbers_table.word%type
);
number_record number_record_definition;
BEGIN
SELECT * INTO number_record FROM numbers_table;
INSERT INTO aux_numbers_table VALUES number_record;
END;
CALL proc_insert_select_resultset();
SELECT * FROM aux_numbers_table;
|AUX_NUM|AUX_WORD|
|-------|--------|
|1 |one |
Snowflake¶
CREATE OR REPLACE PROCEDURE proc_insert_select_resultset ()
RETURNS VARCHAR
LANGUAGE SQL
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"oracle"}}'
EXECUTE AS CALLER
AS
$$
DECLARE
!!!RESOLVE EWI!!! /*** SSC-EWI-0056 - CUSTOM TYPES ARE NOT SUPPORTED IN SNOWFLAKE BUT REFERENCES TO THIS CUSTOM TYPE WERE CHANGED TO OBJECT ***/!!!
TYPE number_record_definition IS RECORD(
rec_num numbers_table.num%type,
rec_word numbers_table.word%type
);
number_record OBJECT !!!RESOLVE EWI!!! /*** SSC-EWI-0036 - number_record_definition DATA TYPE CONVERTED TO OBJECT ***/!!! := OBJECT_CONSTRUCT();
BEGIN
SELECT
OBJECT_CONSTRUCT( *) INTO
:number_record
FROM
numbers_table;
INSERT INTO aux_numbers_table
SELECT
:number_record:REC_NUM,
:number_record:REC_WORD;
END;
$$;
CALL proc_insert_select_resultset();
SELECT * FROM
aux_numbers_table;
CREATE OR REPLACE PROCEDURE PUBLIC.proc_select_into()
RETURNS INTEGER
LANGUAGE SQL
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"oracle"}}'
AS
$$
DECLARE
NUMBER_VARIABLE INTEGER;
WORD_VARIABLE VARCHAR;
NUMBER_RECORD RESULTSET;
BEGIN
LET c2 CURSOR FOR NUMBER_RECORD;
FOR row_variable IN c2 DO
let var1 integer := row_variable.num;
let var2 varchar := row_variable.word;
INSERT INTO PUBLIC.aux_numbers_table VALUES(:var1, :var2);
END FOR;
end;
$$;
|AUX_NUM|AUX_WORD|
|-------|--------|
|1 |one |
Problemas conhecidos¶
1. Limitation in the use of RESULTSET¶
RESULTSET é muito limitado em seu uso. Se a instrução table(result_scan(last_query_id())
, deve ser usada logo após a execução da consulta RESULTSET. Para obter mais informações, consulte este link.
EWIs relacionados¶
SSC-EWI-0036: Tipo de dados convertido em outro tipo de dados.
SSC-EWI-0056: Create Type não tem suporte.
PACKAGES¶
Descrição¶
Use a instrução CREATE
PACKAGE
para criar a especificação de um pacote armazenado, que é uma coleção encapsulada de procedimentos relacionados, funções e outros objetos de programa armazenados juntos no banco de dados. A especificação do pacote declara esses objetos. O corpo do pacote, especificado posteriormente, define esses objetos. (Instrução CREATE PACKAGE da referência de linguagem Oracle PL/SQL)
O Snowflake não tem um equivalente para os pacotes Oracle, portanto, para manter a estrutura, os pacotes são transformados em um esquema, e todos os seus elementos são definidos dentro dele. Além disso, o pacote e seus elementos são renomeados para preservar o nome do esquema original. Para obter mais informações sobre a renomeação de pacotes, consulte a seção Opções de conversão de pacotes.
BODY¶
Descrição¶
O cabeçalho de PACKAGE BODY é removido e cada procedimento ou definição de função é transformado em uma função ou procedimento autônomo.
CREATE [ OR REPLACE ]
[ EDITIONABLE | NONEDITIONABLE ]
PACKAGE BODY plsql_package_body_source
Amostra de padrões da origem¶
Nota
As consultas a seguir foram transformadas com a opção PackagesAsSchema desativada.
Oracle¶
CREATE OR REPLACE PACKAGE BODY SCHEMA1.PKG1 AS
PROCEDURE procedure1 AS
BEGIN
dbms_output.put_line('hello world');
END;
END package1;
Snowflake¶
CREATE OR REPLACE PROCEDURE SCHEMA1_PKG1.procedure1 ()
RETURNS VARCHAR
LANGUAGE SQL
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"oracle"}}'
EXECUTE AS CALLER
AS
$$
BEGIN
--** SSC-FDM-OR0035 - CHECK UDF IMPLEMENTATION FOR DBMS_OUTPUT.PUT_LINE_UDF. **
CALL DBMS_OUTPUT.PUT_LINE_UDF('hello world');
END;
$$;
Problemas conhecidos¶
Não foram encontrados problemas.
EWIs relacionados¶
SSC-FDM-OR0035: DBMS_OUTPUT.PUTLINE verifique a implementação de UDF.
Constantes¶
Descrição¶
PACKAGE CONSTANTS pode ser declarado na declaração do pacote ou em PACKAGE BODY. Quando uma constante de pacote é usada em um procedimento, uma nova variável é declarada com o mesmo nome e valor da constante, de modo que o código resultante é bastante semelhante à entrada.
constant CONSTANT datatype [NOT NULL] { := | DEFAULT } expression ;
Amostra de padrões da origem¶
Exemplo de código auxiliar¶
create table table1(id number);
CREATE OR REPLACE TABLE table1 (id NUMBER(38, 18) /*** SSC-FDM-0006 - NUMBER TYPE COLUMN MAY NOT BEHAVE SIMILARLY IN SNOWFLAKE. ***/
)
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"oracle"}}'
;
Oracle¶
CREATE OR REPLACE PACKAGE PKG1 AS
PROCEDURE procedure1;
package_constant CONSTANT NUMBER:= 9999;
END PKG1;
CREATE OR REPLACE PACKAGE BODY PKG1 AS
PROCEDURE procedure1 AS
BEGIN
INSERT INTO TABLE1(ID) VALUES(package_constant);
END;
END PKG1;
CALL PKG1.procedure1();
SELECT * FROM TABLE1;
|ID |
|----|
|9999|
Snowflake¶
CREATE SCHEMA IF NOT EXISTS PKG1
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"oracle"}}'
;
CREATE OR REPLACE PROCEDURE PKG1.procedure1 ()
RETURNS VARCHAR
LANGUAGE SQL
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"oracle"}}'
EXECUTE AS CALLER
AS
$$
DECLARE
PACKAGE_CONSTANT NUMBER := 9999;
BEGIN
INSERT INTO TABLE1(ID) VALUES(:PACKAGE_CONSTANT);
END;
$$;
CALL PKG1.procedure1();
SELECT * FROM
TABLE1;
|ID |
|----|
|9999|
Nota
Observe que a definiçãoPROCEDURE
está sendo removida, pois não é necessária no Snowflake.
Problemas conhecidos¶
Não foram encontrados problemas.
EWIs relacionados¶
SSC-FDM-0006: A coluna de tipo de número pode não se comportar de forma semelhante no Snowflake.
DECLARATION¶
Descrição¶
A declaração é convertida em um esquema, de modo que cada elemento interno é declarado dentro desse esquema. Todos os elementos presentes no pacote são comentados, exceto VARIABLES, que tem uma transformação adequada.
CREATE [ OR REPLACE ]
[ EDITIONABLE | NONEDITIONABLE ]
PACKAGE plsql_package_source
Amostra de padrões da origem¶
Nota
As consultas a seguir foram transformadas com a opção PackagesAsSchema desativada.
Oracle¶
CREATE OR REPLACE PACKAGE SCHEMA1.PKG1 AS
-- Function Declaration
FUNCTION function_declaration(param1 VARCHAR) RETURN INTEGER;
-- Procedure Declaration
PROCEDURE procedure_declaration(param1 VARCHAR2, param2 VARCHAR2);
END PKG1;
Snowflake¶
CREATE SCHEMA IF NOT EXISTS SCHEMA1_PKG1
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"oracle"}}'
;
Nota
Observe que as definições de FUNCTION
e PROCEDURE
estão sendo removidas, pois não são necessárias no Snowflake.
Problemas conhecidos¶
Não foram encontrados problemas.
EWIs relacionados¶
Sem EWIs relacionados.
VARIABLES¶
Descrição¶
PACKAGE VARIABLES pode ser declarado na declaração do pacote ou em PACKAGE BODY. Devido ao seu comportamento, essas variáveis são convertidas em variáveis de sessão do Snowflake, de modo que cada uso ou atribuição é convertido para seu equivalente no Snowflake.
variable datatype [ [ NOT NULL] {:= | DEFAULT} expression ] ;
Amostra de padrões da origem¶
Exemplo de código auxiliar¶
create table table1(id number);
CREATE OR REPLACE TABLE table1 (id NUMBER(38, 18) /*** SSC-FDM-0006 - NUMBER TYPE COLUMN MAY NOT BEHAVE SIMILARLY IN SNOWFLAKE. ***/
)
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"oracle"}}'
;
Declaração de variáveis¶
Oracle¶
CREATE OR REPLACE PACKAGE PKG1 AS
package_variable NUMBER:= 100;
END PKG1;
Script Snowflake¶
CREATE SCHEMA IF NOT EXISTS PKG1
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"oracle"}}'
;
SET "PKG1.PACKAGE_VARIABLE" = '' || (100);
Uso de variáveis¶
Os usos de variáveis de pacote são transformados na função do Snowflake GETVARIABLE que acessa o valor atual de uma variável de sessão. Uma conversão explícita é adicionada ao tipo de dados da variável original para manter a equivalência funcional nas operações em que essas variáveis são usadas.
Oracle¶
CREATE OR REPLACE PACKAGE PKG1 AS
PROCEDURE procedure1;
package_variable NUMBER:= 100;
END PKG1;
CREATE OR REPLACE PACKAGE BODY PKG1 AS
PROCEDURE procedure1 AS
BEGIN
INSERT INTO TABLE1(ID) VALUES(package_variable);
END;
END PKG1;
CALL SCHEMA1.PKG1.procedure1();
SELECT * FROM TABLE1;
|ID |
|---|
|100|
Snowflake¶
CREATE SCHEMA IF NOT EXISTS PKG1
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"oracle"}}'
;
SET "PKG1.PACKAGE_VARIABLE" = '' || (100);
CREATE OR REPLACE PROCEDURE PKG1.procedure1 ()
RETURNS VARCHAR
LANGUAGE SQL
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"oracle"}}'
EXECUTE AS CALLER
AS
$$
BEGIN
INSERT INTO TABLE1(ID) VALUES(GETVARIABLE('PKG1.PACKAGE_VARIABLE') :: NUMBER);
END;
$$;
CALL SCHEMA1.PKG1.procedure1();
SELECT * FROM
TABLE1;
|ID |
|---|
|100|
Nota
Observe que a definição de PROCEDURE
no pacote foi removida, pois não é exigida pelo Snowflake.
Atribuição regular variável¶
Quando uma variável de pacote é atribuída usando o operador :=
, a atribuição é substituída por uma SnowConvert UDF chamada UPDATE_PACKAGE_VARIABLE_STATE que é uma abstração da função do Snowflake SETVARIABLE.
Oracle
CREATE OR REPLACE PACKAGE PKG1 AS
PROCEDURE procedure1;
package_variable NUMBER:= 100;
END PKG1;
CREATE OR REPLACE PACKAGE BODY PKG1 AS
PROCEDURE procedure1 AS
BEGIN
package_variable := package_variable + 100;
INSERT INTO TABLE1(ID) VALUES(package_variable);
END;
END PKG1;
CALL PKG1.procedure1();
SELECT * FROM TABLE1;
|ID |
|---|
|200|
Snowflake
CREATE SCHEMA IF NOT EXISTS PKG1
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"oracle"}}'
;
SET "PKG1.PACKAGE_VARIABLE" = '' || (100);
CREATE OR REPLACE PROCEDURE PKG1.procedure1 ()
RETURNS VARCHAR
LANGUAGE SQL
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"oracle"}}'
EXECUTE AS CALLER
AS
$$
BEGIN
CALL UPDATE_PACKAGE_VARIABLE_STATE_UDF('PKG1.PACKAGE_VARIABLE', TO_VARCHAR(GETVARIABLE('PKG1.PACKAGE_VARIABLE') :: NUMBER + 100));
INSERT INTO TABLE1(ID) VALUES(GETVARIABLE('PKG1.PACKAGE_VARIABLE') :: NUMBER);
END;
$$;
CALL PKG1.procedure1();
SELECT * FROM
TABLE1;
|ID |
|---|
|200|
Nota
Observe que a definição de PROCEDURE
no pacote foi removida, pois não é exigida pelo Snowflake.
Atribuição de variável como argumento de saída¶
Quando uma variável de pacote é usada como argumento de saída, uma nova variável é declarada dentro do procedimento, essa variável capturará o valor do argumento de saída do procedimento e, em seguida, a variável será usada para atualizar a variável de sessão que se refere à variável de pacote usando o método UPDATE_PACKAGE_VARIABLE_STATE mencionado acima. Para obter mais informações, consulte transformação de parâmetros de saída.
Oracle¶
CREATE OR REPLACE PACKAGE PKG1 AS
PROCEDURE procedure1;
PROCEDURE procedure2(out_param OUT NUMBER);
package_variable NUMBER:= 100;
END PKG1;
CREATE OR REPLACE PACKAGE BODY PKG1 AS
PROCEDURE procedure1 AS
BEGIN
procedure2(package_variable);
INSERT INTO TABLE1(ID) VALUES(package_variable);
END;
PROCEDURE procedure2 (out_param OUT NUMBER) AS
BEGIN
out_param := 1000;
END;
END PKG1;
CALL PKG1.procedure1();
|ID |
|----|
|1000|
Snowflake¶
CREATE SCHEMA IF NOT EXISTS PKG1
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"oracle"}}'
;
SET "PKG1.PACKAGE_VARIABLE" = '' || (100);
CREATE OR REPLACE PROCEDURE PKG1.procedure1 ()
RETURNS VARCHAR
LANGUAGE SQL
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"oracle"}}'
EXECUTE AS CALLER
AS
$$
DECLARE
PKG1_PACKAGE_VARIABLE VARIANT;
call_results VARIANT;
BEGIN
call_results := (
CALL PKG1.
procedure2(:PKG1_PACKAGE_VARIABLE)
);
PKG1_PACKAGE_VARIABLE := :call_results;
CALL UPDATE_PACKAGE_VARIABLE_STATE_UDF('PKG1.PACKAGE_VARIABLE', TO_VARCHAR(:PKG1_PACKAGE_VARIABLE));
INSERT INTO TABLE1(ID) VALUES(GETVARIABLE('PKG1.PACKAGE_VARIABLE') :: NUMBER);
END;
$$;
CREATE OR REPLACE PROCEDURE PKG1.procedure2 (out_param NUMBER(38, 18))
RETURNS VARIANT
LANGUAGE SQL
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"oracle"}}'
EXECUTE AS CALLER
AS
$$
BEGIN
out_param := 1000;
RETURN null;
END;
$$;
CALL PKG1.procedure1();
|ID |
|----|
|1000|
Nota
Observe que a definição de PROCEDURE
no pacote foi removida, pois não é exigida pelo Snowflake.
Problemas conhecidos¶
Não foram encontrados problemas.
EWIs relacionados¶
SSC-FDM-0006: A coluna de tipo de número pode não se comportar de forma semelhante no Snowflake.
COLLECTIONS AND RECORDS¶
Aviso
Esta seção é um trabalho em andamento, as informações podem mudar no futuro.
Descrição geral¶
PL/SQL permite que você defina dois tipos de dados compostos: coleção e registro, em que composto é um tipo de dados que armazena valores que têm componentes internos.
Em uma coleção, os componentes internos sempre têm o mesmo tipo de dados e são chamados de elementos.
Em um registro, os componentes internos podem ter diferentes tipos de dados e são chamados de campos. (COLLECTIONS AND RECORDS da referência de linguagem Oracle PL/SQL)
Nota
Leve em consideração a referência de conversão da instrução CREATE TYPE, pois algumas soluções alternativas podem se sobrepor e podem ser funcionais em ambos os cenários.
Limitações¶
O Snowflake não oferece suporte a tipos de dados definidos pelo usuário, o que inclui Coleções e registros PL, de acordo com a documentação on-line Tipos de dados sem suporte, mas oferece suporte a Tipos de dados semiestruturados, que podem ser usados para imitar a estrutura hierárquica do registro e a estrutura de elementos dos tipos definidos pelo usuário da coleção. Por esse motivo, há vários tipos de recursos que não têm solução alternativa.
A seguir, os recursos para os quais NO propõe uma solução alternativa:
O tamanho da variável não pode exceder 16MB¶
O Snowflake define o tamanho máximo de VARIANT, OBJECT e ARRAY em 16MBs. Isso significa que, se um registro, uma coleção ou qualquer elemento de qualquer um deles exceder esse tamanho, isso causará um erro de tempo de execução.
A capacidade do varray não pode ser limitada¶
Os varrays da Oracle oferecem a capacidade de limitar o número de elementos dentro deles. Isso não é suportado pelo Snowflake.
Proposta de solução alternativa¶
Sobre a definição dos tipos de registro¶
A solução proposta é usar um tipo de dados semiestruturado «OBJECT» para imitar o tipo de dados da Oracle.
Sobre a definição dos tipos de coleção¶
Há duas soluções alternativas diferentes que dependem do tipo de coleção a ser migrada:
Matrizes associativas têm proposta para alteração para um tipo de dados semiestruturados «OBJECT».
Propõe-se que as matrizes e as matrizes de tabelas aninhadas sejam transformadas em um tipo de dados semiestruturado «ARRAY».
Suporte atual do SnowConvert¶
A próxima tabela mostra um resumo do suporte atual fornecido pela ferramenta SnowConvert. Você deve levar em conta que as conversões podem ainda não ser definitivas e que pode ser necessário mais trabalho.
Sub-Feature | Current recognition status | Current translation status | Has Known Workarounds |
---|---|---|---|
Record Type Definitions | Recognized. | Not Translated. | Yes. |
Associative Array Type Definitions | Not Recognized. | Not Translated. | Yes. |
Varray Type Definitions | Recognized. | Not Translated. | Yes. |
Nested Table Array Type Definitions | Recognized. | Not Translated. | Yes. |
Problemas conhecidos¶
1. Associate Arrays are considered a Nested Table¶
Até o momento, o SnowConvert não faz distinção entre uma matriz associativa e uma tabela aninhada, o que significa que elas são misturadas nas mesmas contagens de avaliação.
EWIs relacionados¶
Sem EWIs relacionados.
Definição do tipo de matriz associativa¶
Aviso
Esta seção é um trabalho em andamento, as informações podem mudar no futuro.
Nota
Algumas partes do código de saída foram omitidas por motivos de clareza.
Descrição¶
Uma matriz associativa (anteriormente chamada de tabela ou índice-por-tabela PL/SQL) é um conjunto de pares chave-valor. Cada chave é um índice exclusivo, usado para localizar o valor associado com a sintaxe variable_name(index)
.
O tipo de dados de index
pode ser do tipo cadeia de caracteres (VARCHAR2
, VARCHAR
, STRING
ou LONG
) ou PLS_INTEGER
. Os índices são armazenados em ordem de classificação, não em ordem de criação. Para os tipos de cadeia de caracteres, a ordem de classificação é determinada pelos parâmetros de inicialização NLS_SORT
e NLS_COMP
.
(ASSOCIATIVE ARRAYS da referência de linguagem Oracle PL/SQL)
Aviso
Não confundir com a definição do tipo PL/SQL NESTED TABLE .
Para a conversão, a definição do tipo é substituída por um OBJECT Tipo de dados semiestruturados e, em seguida, seus usos são alterados de acordo com todas as operações.
Para definir um tipo de matriz associativa, a sintaxe é a seguinte:
type_definition := TYPE IS TABLE OF datatype INDEX BY indexing_datatype;
indexing_datatype := { PLS_INTEGER
| BINARY_INTEGER
| string_datatype
}
Para declarar uma variável desse tipo:
variable_name collection_type;
Amostra de padrões da origem¶
Matriz associativa indexada a Varchar¶
Oracle¶
CREATE OR REPLACE PROCEDURE associative_array
IS
TYPE associate_array_typ IS TABLE OF INTEGER
INDEX BY VARCHAR2(50);
associate_array associate_array_typ := associate_array_typ();
associate_index VARCHAR2(50);
BEGIN
associate_array('abc') := 1;
associate_array('bca') := 2;
associate_array('def') := 3;
DBMS_OUTPUT.PUT_LINE(associate_array('abc'));
associate_array('abc') := 4;
--THROWS 'NO DATA FOUND'
--DBMS_OUTPUT.PUT_LINE(associate_array('no exists'));
DBMS_OUTPUT.PUT_LINE(associate_array.COUNT);
associate_index := associate_array.FIRST;
WHILE associate_index IS NOT NULL
LOOP
DBMS_OUTPUT.PUT_LINE(associate_array(associate_index));
associate_index := associate_array.NEXT(associate_index);
END LOOP;
END;
CALL associative_array();
DBMS OUTPUT
-----------
1
3
4
2
3
Snowflake¶
Observe o parâmetro “true” no OBJECT_INSERT. Isso serve para que o elemento seja atualizado se já estiver presente na matriz.
CREATE OR REPLACE PROCEDURE PUBLIC.associative_array ()
RETURNS VARCHAR
LANGUAGE SQL
EXECUTE AS CALLER
AS
$$
DECLARE
associate_array OBJECT := OBJECT_CONSTRUCT();
associate_index VARCHAR(50);
BEGIN
associate_array := OBJECT_INSERT(associate_array, 'abc', 1, true);
associate_array := OBJECT_INSERT(associate_array, 'bca', 2, true);
associate_array := OBJECT_INSERT(associate_array, 'def', 3, true);
CALL DBMS_OUTPUT.PUT_LINE(:associate_array['abc']);
CALL DBMS_OUTPUT.PUT_LINE(:associate_array['not found']);
associate_array := OBJECT_INSERT(:associate_array, 'abc', 4, true);
CALL DBMS_OUTPUT.PUT_LINE(ARRAY_SIZE(OBJECT_KEYS(:associate_array)));
FOR i IN 1 TO ARRAY_SIZE(OBJECT_KEYS(:associate_array))
LOOP
associate_index := OBJECT_KEYS(:associate_array)[:i-1];
CALL DBMS_OUTPUT.PUT_LINE(:associate_array[:associate_index]);
END LOOP;
END;
$$;
CALL PUBLIC.associative_array();
SELECT * FROM DBMS_OUTPUT.DBMS_OUTPUT_LOG;
DBMS OUTPUT
-----------
1
3
4
2
3
Matriz associativa com índice numérico¶
Oracle¶
CREATE OR REPLACE PROCEDURE numeric_associative_array
IS
TYPE numeric_associative_array_typ IS TABLE OF INTEGER
INDEX BY PLS_INTEGER;
associate_array numeric_associativ
e_array_typ := numeric_associative_array_typ();
associate_index PLS_INTEGER;
BEGIN
associate_array(1) := -1;
associate_array(2) := -2;
associate_array(3) := -3;
DBMS_OUTPUT.PUT_LINE(associate_array(1));
associate_array(1) := -4;
DBMS_OUTPUT.PUT_LINE(associate_array.COUNT);
associate_index := associate_array.FIRST;
WHILE associate_index IS NOT NULL
LOOP
DBMS_OUTPUT.PUT_LINE(associate_array(associate_index));
associate_index := associate_array.NEXT(associate_index);
END LOOP;
END;
CALL numeric_associative_array();
DBMS OUTPUT
-----------
-1
3
-4
-2
-3
Snowflake¶
Observe que o valor numérico é convertido em varchar de acordo com a necessidade da operação. Além disso, observe o parâmetro “true” em OBJECT_INSERT. Isso serve para que o elemento seja atualizado se já estiver presente na matriz.
CREATE OR REPLACE PROCEDURE PUBLIC.numeric_associative_array ()
RETURNS VARCHAR
LANGUAGE SQL
EXECUTE AS CALLER
AS
$$
DECLARE
associate_array OBJECT := OBJECT_CONSTRUCT();
associate_index NUMBER;
BEGIN
associate_array := OBJECT_INSERT(associate_array, '1', -1, true);
associate_array := OBJECT_INSERT(associate_array, '2', -2, true);
associate_array := OBJECT_INSERT(associate_array, '3', -3, true);
CALL DBMS_OUTPUT.PUT_LINE(:associate_array['1']);
associate_array := OBJECT_INSERT(:associate_array, '1', -4, true);
CALL DBMS_OUTPUT.PUT_LINE(ARRAY_SIZE(OBJECT_KEYS(:associate_array)));
FOR i IN 1 TO ARRAY_SIZE(OBJECT_KEYS(:associate_array))
LOOP
associate_index := OBJECT_KEYS(:associate_array)[:i-1];
CALL DBMS_OUTPUT.PUT_LINE(:associate_array[:associate_index::VARCHAR]);
END LOOP;
END;
$$;
CALL PUBLIC.numeric_associative_array();
SELECT * FROM DBMS_OUTPUT.DBMS_OUTPUT_LOG;
DBMS OUTPUT
-----------
-1
3
-4
-2
-3
Matriz associativa indexada numérica de elemento de registro¶
Nesse caso, a matriz associativa é composta por uma estrutura de registro, e essa estrutura precisa ser preservada. Para isso, foram adicionadas outras operações de inserção.
Oracle¶
CREATE OR REPLACE PROCEDURE record_associative_array
IS
TYPE record_typ IS RECORD(col1 INTEGER);
TYPE record_associative_array_typ IS TABLE OF record_typ
INDEX BY PLS_INTEGER;
associate_array record_associati ve_array_typ := record_associative_array_typ();
associate_index PLS_INTEGER;
BEGIN
associate_array(1).col1 := -1;
associate_array(2).col1 := -2;
associate_array(3).col1 := -3;
DBMS_OUTPUT.PUT_LINE(associate_array(1).col1);
associate_array(4).col1 := -4;
DBMS_OUTPUT.PUT_LINE(associate_array.COUNT);
associate_index := associate_array.FIRST;
WHILE associate_index IS NOT NULL
LOOP
DBMS_OUTPUT.PUT_LINE(associate_array(associate_index).col1);
associate_index := associate_array.NEXT(associate_index);
END LOOP;
END;
/
CALL record_associative_array();
DBMS OUTPUT
-----------
-1
3
-4
-2
-3
Snowflake¶
Nesse cenário, a inserção/atualização pressupõe a criação automática do registro dentro da matriz associativa e isso precisa ser levado em conta ao criar novos registros.
CREATE OR REPLACE PROCEDURE PUBLIC.record_associative_array ()
RETURNS VARCHAR
LANGUAGE SQL
EXECUTE AS CALLER
AS
$$
DECLARE
associate_array OBJECT := OBJECT_CONSTRUCT();
associate_index NUMBER;
BEGIN
associate_array := OBJECT_INSERT(associate_array, '1', OBJECT_INSERT(NVL(associate_array['1'], OBJECT_CONSTRUCT()), 'col1', -1, true), true);
associate_array := OBJECT_INSERT(associate_array, '2', OBJECT_INSERT(NVL(associate_array['2'], OBJECT_CONSTRUCT()), 'col1', -2, true), true);
associate_array := OBJECT_INSERT(associate_array, '3', OBJECT_INSERT(NVL(associate_array['3'], OBJECT_CONSTRUCT()), 'col1', -3, true), true);
CALL DBMS_OUTPUT.PUT_LINE(:associate_array['1']:col1);
associate_array := OBJECT_INSERT(associate_array, '1', OBJECT_INSERT(NVL(associate_array['1'], OBJECT_CONSTRUCT()), 'col1', -4, true), true);
CALL DBMS_OUTPUT.PUT_LINE(ARRAY_SIZE(OBJECT_KEYS(:associate_array)));
FOR i IN 1 TO ARRAY_SIZE(OBJECT_KEYS(:associate_array))
LOOP
associate_index := OBJECT_KEYS(:associate_array)[:i-1];
CALL DBMS_OUTPUT.PUT_LINE(:associate_array[:associate_index::VARCHAR]:col1);
END LOOP;
END;
$$;
CALL PUBLIC.record_associative_array();
SELECT * FROM DBMS_OUTPUT.DBMS_OUTPUT_LOG;
DBMS OUTPUT
-----------
-1
3
-4
-2
-3
Problemas conhecidos¶
1. They are currently not being recognized¶
O SnowConvert trata essas coleções como matrizes de tabelas aninhadas. Há um item de trabalho para corrigir isso.
EWIs relacionados¶
Sem EWIs relacionados.
Métodos de coleta¶
Aviso
Esta seção é um trabalho em andamento, as informações podem mudar no futuro
Nota
Algumas partes do código de saída foram omitidas por motivos de clareza.
Descrição¶
Um método de coleção é um subprograma PL/SQL - uma função que retorna informações sobre uma coleção ou um procedimento que opera em uma coleção. Os métodos de coleção tornam as coleções mais fáceis de usar e os aplicativos mais fáceis de manter.
(COLLECTION METHODS da referência de linguagem Oracle PL/SQL)
Alguns desses métodos podem ser mapeados para operações semiestruturadas nativas do Snowflake. Os que não puderem ou tiverem diferenças serão mapeados para uma implementação de UDF.
Suporte atual do SnowConvert¶
A próxima tabela mostra um resumo do suporte atual fornecido pela ferramenta SnowConvert. Você deve levar em conta que as conversões podem ainda não ser definitivas e que pode ser necessário mais trabalho.
Method | Current recognition status | Current translation status | Mapped to |
---|---|---|---|
DELETE | Not Recognized. | Not Translated. | UDF |
TRIM | Not Recognized. | Not Translated. | UDF (To be defined) |
EXTEND | Not Recognized. | Not Translated. | UDF |
EXISTS | Not Recognized. | Not Translated. | ARRAY_CONTAINS |
FIRST | Not Recognized. | Not Translated. | UDF |
LAST | Not Recognized. | Not Translated. | UDF |
COUNT | Not Recognized. | Not Translated. | ARRAY_SIZE |
LIMIT | Not Recognized. | Not Translated. | Not Supported. |
PRIOR | Not Recognized. | Not Translated. | UDF (To be defined) |
NEXT | Not Recognized. | Not Translated. | UDF (To be defined) |
Amostra de padrões da origem¶
COUNT¶
Esse método retorna a contagem de elementos «não definidos» (não confundir com nulos) em uma coleção (as tabelas aninhadas podem se tornar esparsas, deixando esses elementos no meio). Em matrizes associativas, ele retorna o número de chaves na matriz.
Oracle¶
CREATE OR REPLACE PROCEDURE collection_count
IS
TYPE varray_typ IS VARRAY(5) OF INTEGER;
TYPE nt_typ IS TABLE OF INTEGER;
TYPE aa_typ IS TABLE OF INTEGER INDEX BY VARCHAR2(20);
associative_array aa_typ := aa_typ('abc'=>1, 'bca'=>1);
varray_variable varray_typ := varray_typ(1, 2, 3);
nt_variable nt_typ := nt_typ(1, 2, 3, 4);
BEGIN
DBMS_OUTPUT.PUT_LINE(associative_array.COUNT);
DBMS_OUTPUT.PUT_LINE(varray_variable.COUNT);
DBMS_OUTPUT.PUT_LINE(nt_variable.COUNT);
END;
CALL collection_count();
DBMS OUTPUT
-----------
2
3
4
Snowflake¶
O equivalente no Snowflake é o método ARRAY_SIZE.
CREATE OR REPLACE PROCEDURE PUBLIC.collection_count()
RETURNS VARCHAR
LANGUAGE SQL
EXECUTE AS CALLER
AS
$$
DECLARE
associative_array OBJECT := OBJECT_CONSTRUCT('abc', 1, 'bca', 1);
varray_variable ARRAY := ARRAY_CONSTRUCT(1, 2, 3);
nt_variable ARRAY := ARRAY_CONSTRUCT(1, 2, 3, 4);
BEGIN
CALL DBMS_OUTPUT.PUT_LINE(ARRAY_SIZE(OBJECT_KEYS(:associative_array)));
CALL DBMS_OUTPUT.PUT_LINE(ARRAY_SIZE(:varray_variable));
CALL DBMS_OUTPUT.PUT_LINE(ARRAY_SIZE(:nt_variable));
END;
$$;
CALL PUBLIC.collection_count();
SELECT * FROM DBMS_OUTPUT.DBMS_OUTPUT_LOG;
DBMS OUTPUT
-----------
2
3
4
EXISTS¶
Esse método retorna True se o elemento fornecido estiver contido na coleção. Em arrays associativos, ele testa se a chave está contida.
Oracle¶
CREATE OR REPLACE PROCEDURE collection_exists
IS
TYPE nt_typ IS TABLE OF INTEGER;
TYPE aa_typ IS TABLE OF INTEGER INDEX BY VARCHAR2(20);
associative_array aa_typ := aa_typ('abc'=>1, 'bca'=>1);
nt_variable nt_typ := nt_typ(1, 2, 3, 4);
BEGIN
IF associative_array.EXISTS('abc')
THEN DBMS_OUTPUT.PUT_LINE('Found');
END IF;
IF NOT associative_array.EXISTS('not found')
THEN DBMS_OUTPUT.PUT_LINE('Not found');
END IF;
IF nt_variable.EXISTS(1)
THEN DBMS_OUTPUT.PUT_LINE('Found');
END IF;
IF NOT nt_variable.EXISTS(5)
THEN DBMS_OUTPUT.PUT_LINE('Not found');
END IF;
END;
/
CALL collection_exists();
DBMS OUTPUT
-----------
2
3
4
Snowflake¶
O equivalente no Snowflake é o método ARRAY_CONTAINS. Observe que, ao usar elementos Varchar, é necessário fazer a conversão para Variant.
CREATE OR REPLACE PROCEDURE PUBLIC.collection_exists()
RETURNS VARCHAR
LANGUAGE SQL
EXECUTE AS CALLER
AS
$$
DECLARE
associative_array OBJECT := OBJECT_CONSTRUCT('abc', 1, 'bca', 1);
nt_variable ARRAY := ARRAY_CONSTRUCT(1, 2, 3, 4);
BEGIN
IF (ARRAY_CONTAINS('abc'::VARIANT, OBJECT_KEYS(associative_array)))
THEN CALL DBMS_OUTPUT.PUT_LINE('Found');
END IF;
IF (NOT ARRAY_CONTAINS('not found'::VARIANT, OBJECT_KEYS(associative_array)))
THEN CALL DBMS_OUTPUT.PUT_LINE('Not found');
END IF;
IF (ARRAY_CONTAINS(1, nt_variable))
THEN CALL DBMS_OUTPUT.PUT_LINE('Found');
END IF;
IF (NOT ARRAY_CONTAINS(5, nt_variable))
THEN CALL DBMS_OUTPUT.PUT_LINE('Not found');
END IF;
END;
$$;
CALL PUBLIC.collection_exists();
SELECT * FROM DBMS_OUTPUT.DBMS_OUTPUT_LOG;
DBMS OUTPUT
-----------
2
3
4
FIRST/LAST¶
Esses dois métodos retornam o primeiro/último elemento da coleção, respectivamente. Se a coleção estiver vazia, ele retornará null. Essa operação é mapeada para um UDF, que será adicionado em revisões futuras.
Oracle¶
CREATE OR REPLACE PROCEDURE collection_first_last
IS
TYPE nt_typ IS TABLE OF INTEGER;
TYPE aa_typ IS TABLE OF INTEGER INDEX BY VARCHAR2(20);
associative_array aa_typ := aa_typ('abc'=>1, 'bca'=>1);
nt_variable nt_typ := nt_typ();
BEGIN
DBMS_OUTPUT.PUT_LINE(associative_array.FIRST);
DBMS_OUTPUT.PUT_LINE(associative_array.LAST);
DBMS_OUTPUT.PUT_LINE(nt_variable.FIRST);
DBMS_OUTPUT.PUT_LINE(nt_variable.LAST);
nt_variable := nt_typ(1, 2, 3, 4);
DBMS_OUTPUT.PUT_LINE(nt_variable.FIRST);
DBMS_OUTPUT.PUT_LINE(nt_variable.LAST);
END;
/
CALL collection_first_last();
DBMS OUTPUT
-----------
abc
bca
--These empty spaces are due to it evaluating to null
1
4
Snowflake¶
CREATE OR REPLACE PROCEDURE PUBLIC.collection_first_last()
RETURNS VARCHAR
LANGUAGE SQL
EXECUTE AS CALLER
AS
$$
DECLARE
associative_array OBJECT := OBJECT_CONSTRUCT('abc', 1, 'bca', 1);
nt_variable ARRAY := ARRAY_CONSTRUCT();
BEGIN
CALL DBMS_OUTPUT.PUT_LINE(ARRAY_FIRST(:associative_array));
CALL DBMS_OUTPUT.PUT_LINE(ARRAY_LAST(:associative_array));
CALL DBMS_OUTPUT.PUT_LINE(ARRAY_FIRST(:nt_variable));
CALL DBMS_OUTPUT.PUT_LINE(ARRAY_LAST(:nt_variable));
nt_variable := ARRAY_CONSTRUCT(1, 2, 3, 4);
CALL DBMS_OUTPUT.PUT_LINE(ARRAY_FIRST(:nt_variable));
CALL DBMS_OUTPUT.PUT_LINE(ARRAY_LAST(:nt_variable));
END;
$$;
CALL PUBLIC.collection_first_last();
SELECT * FROM DBMS_OUTPUT.DBMS_OUTPUT_LOG;
CREATE OR REPLACE FUNCTION ARRAY_FIRST(array_variable VARIANT)
RETURNS VARIANT
LANGUAGE SQL
AS
$$
IFF (IS_OBJECT(array_variable),
ARRAY_FIRST(OBJECT_KEYS(array_variable)),
IFF (ARRAY_SIZE(array_variable) = 0, null, array_variable[0]))
$$;
CREATE OR REPLACE FUNCTION ARRAY_LAST(array_variable VARIANT)
RETURNS VARIANT
LANGUAGE SQL
AS
$$
IFF (IS_OBJECT(array_variable),
ARRAY_LAST(OBJECT_KEYS(array_variable)),
IFF (ARRAY_SIZE(array_variable) = 0, null, array_variable[ARRAY_SIZE(array_variable)-1]))
$$;
DBMS OUTPUT
-----------
abc
bca
--These empty spaces are due to it evaluating to null
1
4
DELETE¶
Esse método é usado para remover elementos de uma coleção. Ele tem três variantes possíveis:
.DELETE remove todos os elementos.
.DELETE(n) remove o elemento cujo índice corresponde a “n”.
.DELETE(n, m) remove os índices de “n” a “m”.
Nota
No Oracle, o uso dessa operação em tabelas aninhadas faz com que elas tenham elementos «indefinidos» devido ao fato de serem esparsas.
Aviso
Observe que a segunda e a terceira versões não se aplicam a Varrays.
Oracle¶
Para simplificar, esse exemplo verifica apenas o número de elementos, mas pode ser modificado para exibir o conteúdo de cada coleção.
CREATE OR REPLACE PROCEDURE collection_delete
IS
TYPE varray_typ IS VARRAY(5) OF INTEGER;
TYPE nt_typ IS TABLE OF INTEGER;
TYPE aa_typ IS TABLE OF INTEGER INDEX BY VARCHAR2(20);
associative_array1 aa_typ := aa_typ('abc'=>1, 'def'=>2, 'ghi'=>3, 'jkl'=>4);
associative_array2 aa_typ := aa_typ('abc'=>1, 'def'=>2, 'ghi'=>3, 'jkl'=>4);
associative_array3 aa_typ := aa_typ('abc'=>1, 'def'=>2, 'ghi'=>3, 'jkl'=>4);
varray_variable1 varray_typ := varray_typ(1, 2, 3, 4);
nt_variable1 nt_typ := nt_typ(1, 2, 3, 4);
nt_variable2 nt_typ := nt_typ(1, 2, 3, 4);
nt_variable3 nt_typ := nt_typ(1, 2, 3, 4);
BEGIN
varray_variable1.DELETE;--delete everything
nt_variable1.DELETE;--delete everything
nt_variable2.DELETE(2);--delete second position
nt_variable3.DELETE(2, 3);--delete range
associative_array1.DELETE;--delete everything
associative_array2.DELETE('def');--delete second position
associative_array3.DELETE('def', 'jkl');--delete range
DBMS_OUTPUT.PUT_LINE(varray_variable1.COUNT);
DBMS_OUTPUT.PUT_LINE(nt_variable1.COUNT);
DBMS_OUTPUT.PUT_LINE(nt_variable2.COUNT);
DBMS_OUTPUT.PUT_LINE(nt_variable3.COUNT);
DBMS_OUTPUT.PUT_LINE(associative_array1.COUNT);
DBMS_OUTPUT.PUT_LINE(associative_array2.COUNT);
DBMS_OUTPUT.PUT_LINE(associative_array3.COUNT);
END;
/
CALL collection_delete();
DBMS OUTPUT
-----------
0
0
3
2
0
3
1
Snowflake¶
O Snowflake não oferece suporte a exclusões de um ARRAY existente e, por esse motivo, a única solução alternativa oferecida é reconstruir um novo ARRAY dependendo dos parâmetros originais do DELETE.
Nota
Observe que um UDF foi adicionado para implementar a funcionalidade de atualização do elemento.
Este UDF será adicionado em revisões posteriores.
CREATE OR REPLACE PROCEDURE PUBLIC.collection_delete()
RETURNS VARCHAR
LANGUAGE SQL
EXECUTE AS CALLER
AS
$$
DECLARE
associative_array1 OBJECT := OBJECT_CONSTRUCT('abc'=>1, 'def'=>2, 'ghi'=>3, 'jkl'=>4);
associative_array2 OBJECT := OBJECT_CONSTRUCT('abc'=>1, 'def'=>2, 'ghi'=>3, 'jkl'=>4);
associative_array3 OBJECT := OBJECT_CONSTRUCT('abc'=>1, 'def'=>2, 'ghi'=>3, 'jkl'=>4);
varray_variable1 ARRAY := ARRAY_CONSTRUCT(1, 2, 3, 4);
nt_variable1 ARRAY := ARRAY_CONSTRUCT(1, 2, 3, 4);
nt_variable2 ARRAY := ARRAY_CONSTRUCT(1, 2, 3, 4);
nt_variable3 ARRAY := ARRAY_CONSTRUCT(1, 2, 3, 4);
BEGIN
varray_variable1 := ARRAY_CONSTRUCT();--delete everything
nt_variable1 := ARRAY_CONSTRUCT();--delete everything
nt_variable2 := ARRAY_DELETE_UDF(nt_variable2, 2);--delete second position
nt_variable3 := ARRAY_DELETE_UDF(nt_variable3, 2, 3);--delete range
associative_array1 := OBJECT_CONSTRUCT();--delete everything
associative_array2 := ASSOCIATIVE_ARRAY_DELETE_UDF('def');--delete second position
associative_array3 := ASSOCIATIVE_ARRAY_DELETE_UDF('def', 'jkl');--delete range
CALL DBMS_OUTPUT.PUT_LINE(ARRAY_SIZE(varray_variable1));
CALL DBMS_OUTPUT.PUT_LINE(ARRAY_SIZE(nt_variable1);
CALL DBMS_OUTPUT.PUT_LINE(ARRAY_SIZE(nt_variable2);
CALL DBMS_OUTPUT.PUT_LINE(ARRAY_SIZE(nt_variable3);
CALL DBMS_OUTPUT.PUT_LINE(ARRAY_SIZE(associative_array1));
CALL DBMS_OUTPUT.PUT_LINE(ARRAY_SIZE(associative_array2));
CALL DBMS_OUTPUT.PUT_LINE(ARRAY_SIZE(associative_array3));
END;
$$;
CALL PUBLIC.collection_first_last();
SELECT * FROM DBMS_OUTPUT.DBMS_OUTPUT_LOG;
DBMS OUTPUT
-----------
0
0
3
2
0
3
1
EXTEND¶
Esse método é usado para acrescentar novos elementos a uma tabela aninhada ou a Varray. Ele tem três variantes possíveis:
.EXTEND insere um elemento null.
.EXTEND(n) insere “n” elementos null.
.EXTEND(n, i) insere “n” cópias do elemento em “i”.
Oracle¶
CREATE OR REPLACE PROCEDURE collection_extend
IS
TYPE varray_typ IS VARRAY(5) OF INTEGER;
TYPE nt_typ IS TABLE OF INTEGER;
nt_variable1 nt_typ := nt_typ(1, 2, 3, 4);
varray_variable1 varray_typ := varray_typ(1, 2, 3);
varray_variable2 varray_typ := varray_typ(1, 2, 3);
BEGIN
nt_variable1.EXTEND;
varray_variable1.EXTEND(2);
varray_variable2.EXTEND(2, 1);
DBMS_OUTPUT.PUT_LINE(nt_variable1.COUNT);
DBMS_OUTPUT.PUT_LINE(varray_variable1.COUNT);
DBMS_OUTPUT.PUT_LINE(varray_variable2.COUNT);
END;
/
CALL collection_extend();
DBMS OUTPUT
-----------
5
5
5
Snowflake¶
Nota
Observe que um UDF foi adicionado para implementar a funcionalidade de atualização do elemento.
Este UDF será adicionado em revisões posteriores.
CREATE OR REPLACE PROCEDURE PUBLIC.collection_first_last()
RETURNS VARCHAR
LANGUAGE SQL
EXECUTE AS CALLER
AS
$$
DECLARE
nt_variable1 ARRAY := ARRAY_CONSTRUCT(1, 2, 3, 4);
varray_variable1 ARRAY := ARRAY_CONSTRUCT(1, 2, 3);
varray_variable2 ARRAY := ARRAY_CONSTRUCT(1, 2, 3);
BEGIN
nt_variable1 := ARRAY_EXTEND_UDF(nt_variable);
varray_variable1 := ARRAY_EXTEND_UDF(varray_variable1, 2);
varray_variable2 := ARRAY_EXTEND_UDF(varray_variable2, 2, 1);
CALL DBMS_OUTPUT.PUT_LINE(ARRAY_SIZE(nt_variable1);
CALL DBMS_OUTPUT.PUT_LINE(ARRAY_SIZE(varray_variable1));
CALL DBMS_OUTPUT.PUT_LINE(ARRAY_SIZE(varray_variable2));
END;
$$;
CALL PUBLIC.collection_first_last();
SELECT * FROM DBMS_OUTPUT.DBMS_OUTPUT_LOG;
DBMS OUTPUT
-----------
5
5
5
TRIM¶
Esse método é usado para remover os últimos elementos de uma tabela aninhada ou de uma Varray. Ele tem duas variantes possíveis:
.TRIM remove o último elemento.
.TRIM(n) remove os últimos “n” elementos.
Nota
Essa funcionalidade pode ser implementada usando ARRAY_SLICE
Oracle¶
CREATE OR REPLACE PROCEDURE collection_trim
IS
TYPE varray_typ IS VARRAY(5) OF INTEGER;
TYPE nt_typ IS TABLE OF INTEGER;
varray_variable1 varray_typ := varray_typ(1, 2, 3);
nt_variable1 nt_typ := nt_typ(1, 2, 3, 4);
BEGIN
varray_variable1.TRIM;
nt_variable1.TRIM(2);
DBMS_OUTPUT.PUT_LINE(nt_variable1.COUNT);
DBMS_OUTPUT.PUT_LINE(varray_variable1.COUNT);
END;
/
CALL collection_trim();
DBMS OUTPUT
-----------
2
2
LIMIT¶
Esse método retorna o limite máximo de um Varray.
Esse método não é compatível com o Snowflake.
Oracle
CREATE OR REPLACE PROCEDURE collection_limit
IS
TYPE varray_typ1 IS VARRAY(5) OF INTEGER;
TYPE varray_typ2 IS VARRAY(6) OF INTEGER;
varray_variable1 varray_typ1 := varray_typ1(1, 2, 3);
varray_variable2 varray_typ2 := varray_typ2(1, 2, 3, 4);
BEGIN
DBMS_OUTPUT.PUT_LINE(varray_variable1.LIMIT);
DBMS_OUTPUT.PUT_LINE(varray_variable2.LIMIT);
END;
/
CALL collection_limit();
DBMS OUTPUT
-----------
5
6
PRIOR/NEXT
Esse método retorna o índice anterior/próximo, dado um índice. Se não houver um anterior/próximo, ele retornará null. Ele é usado com mais frequência para percorrer uma coleção.
Oracle
CREATE OR REPLACE PROCEDURE collection_prior_next
IS
TYPE varray_typ1 IS VARRAY(5) OF INTEGER;
TYPE aa_typ IS TABLE OF INTEGER INDEX BY VARCHAR2(20);
varray_variable1 varray_typ1 := varray_typ1(-1, -2, -3);
associative_array1 aa_typ := aa_typ('abc'=>1, 'def'=>2, 'ghi'=>3, 'jkl'=>4);
BEGIN
DBMS_OUTPUT.PUT_LINE(varray_variable1.PRIOR(1));
DBMS_OUTPUT.PUT_LINE(varray_variable1.PRIOR(2));
DBMS_OUTPUT.PUT_LINE(varray_variable1.NEXT(2));
DBMS_OUTPUT.PUT_LINE(varray_variable1.NEXT(3));
DBMS_OUTPUT.PUT_LINE(associative_array1.PRIOR('abc'));
DBMS_OUTPUT.PUT_LINE(associative_array1.PRIOR('def'));
DBMS_OUTPUT.PUT_LINE(associative_array1.NEXT('ghi'));
DBMS_OUTPUT.PUT_LINE(associative_array1.NEXT('jkl'));
DBMS_OUTPUT.PUT_LINE(associative_array1.PRIOR('not found'));
END;
/
CALL collection_prior_next();
DBMS OUTPUT
-----------
-- Empty spaces are due to null results
1
3
abc
jkl
jkl
Known Issues
1. Limit method is not supported in Snowflake
O Snowflake não tem suporte para varrays de espaço limitado. Por esse motivo, esse método não é compatível.
Related EWIs
Sem EWIs relacionados
Definição do tipo de matriz de tabela aninhada
Aviso
Esta seção é um trabalho em andamento, as informações podem mudar no futuro.
Nota
Esta seção é para a versão PL/SQL de matrizes de tabela aninhada; para a versão autônoma, consulte Definição de tipo de tabela aninhada.
Nota
Algumas partes do código de saída foram omitidas por motivos de clareza.
Descrição¶
No banco de dados, uma tabela aninhada é um tipo de coluna que armazena um número não especificado de linhas em nenhuma ordem específica.
Quando você recupera um valor de tabela aninhada do banco de dados em uma variável de tabela aninhada PL/SQL, PL/SQL fornece às linhas índices consecutivos, começando em 1. Usando esses índices, você pode acessar as linhas individuais da variável da tabela aninhada. A sintaxe é variable_name(index)
. Os índices e a ordem das linhas de uma tabela aninhada podem não permanecer estáveis à medida que você armazena e recupera a tabela aninhada do banco de dados.
(NESTED TABLES da referência de linguagem Oracle PL/SQL)
Para a conversão, a definição do tipo é substituída por um ARRAY Tipo de dados semiestruturados e, em seguida, seus usos são alterados de acordo com todas as operações. Observe como a conversão para tabelas aninhadas e Varrays é a mesma.
Para definir um tipo de matriz de tabela aninhada, a sintaxe é a seguinte:
type_definition := TYPE IS TABLE OF datatype;
Para declarar uma variável desse tipo:
variable_name collection_type;
Amostra de padrões da origem¶
Definições de matriz de tabela aninhada¶
Isso ilustra como criar diferentes matrizes de tabelas aninhadas e como migrar as definições das variáveis.
Oracle¶
CREATE OR REPLACE PROCEDURE nested_table_procedure
IS
TYPE nested_table_array_typ IS TABLE OF INTEGER;
TYPE nested_table_array_typ2 IS TABLE OF DATE;
nested_table_array nested_table_array_typ;
nested_table_array2 nested_table_array_typ2;
BEGIN
NULL;
END;
Snowflake¶
CREATE OR REPLACE PROCEDURE nested_table_procedure()
RETURNS INTEGER
LANGUAGE SQL
EXECUTE AS CALLER
AS
$$
DECLARE
-- NO LONGER NEEDED
/*
TYPE associative_array_typ IS TABLE OF INTEGER INDEX BY VARCHAR2(30);
TYPE associative_array_typ2 IS TABLE OF INTEGER INDEX BY PLS_INTEGER;
*/
associative_array ARRAY;
associative_array2 ARRAY;
BEGIN
NULL;
END;
$$;
Iteração de tabela aninhada¶
Oracle¶
CREATE OR REPLACE PROCEDURE nested_table_iteration
IS
TYPE nested_table_typ IS TABLE OF INTEGER;
nested_table_variable nested_table_typ := nested_table_typ (10, 20, 30);
BEGIN
FOR i IN 1..nested_table_variable.COUNT
LOOP
DBMS_OUTPUT.PUT_LINE(nested_table_variable(i));
END LOOP;
nested_table_variable (1) := 40;
FOR i IN 1..nested_table_variable.COUNT
LOOP
DBMS_OUTPUT.PUT_LINE(nested_table_variable(i));
END LOOP;
END;
/
CALL nested_table_iteration();
DBMS OUTPUT
-----------
10
20
30
40
20
30
Snowflake¶
Nota
Observe que um UDF foi adicionado para implementar a funcionalidade de atualização do elemento.
Este UDF será adicionado em revisões posteriores.
CREATE OR REPLACE PROCEDURE PUBLIC.nested_table_iteration()
RETURNS VARCHAR
LANGUAGE SQL
EXECUTE AS CALLER
AS
$$
DECLARE
nested_table_variable ARRAY := ARRAY_CONSTRUCT(10, 20, 30);
BEGIN
FOR i IN 1 TO ARRAY_SIZE(nested_table_variable)
LOOP
CALL DBMS_OUTPUT.PUT_LINE(:nested_table_variable[:i-1]);
END LOOP;
nested_table_variable:= INSERT_REPLACE_COLLECTION_ELEMENT_UDF(nested_table_variable, 1, 40);
FOR i IN 1 TO ARRAY_SIZE(nested_table_variable)
LOOP
CALL DBMS_OUTPUT.PUT_LINE(:nested_table_variable[:i-1]);
END LOOP;
END;
$$;
CALL PUBLIC.nested_table_iteration();
SELECT * FROM DBMS_OUTPUT.DBMS_OUTPUT_LOG;
CREATE OR REPLACE FUNCTION PUBLIC.INSERT_REPLACE_COLLECTION_ELEMENT_UDF(varray ARRAY, position INTEGER, newValue VARIANT)
RETURNS ARRAY
LANGUAGE SQL
AS
$$
ARRAY_CAT(
ARRAY_APPEND(ARRAY_SLICE(varray, 0, (position)-1), newValue),
ARRAY_SLICE(varray, position, ARRAY_SIZE(varray)))
$$;
DBMS OUTPUT
-----------
10
20
30
40
20
30
Problemas conhecidos¶
1. They are currently not being converted¶
O SnowConvert não suporta a conversão desses elementos.
2. Indexing needs to be modified¶
Os índices do Oracle começam em 1; no Snowflake, eles começarão em 0.
EWIs relacionados¶
Sem EWIs relacionados
Definição do tipo de registro¶
Aviso
Esta seção é um trabalho em andamento, as informações podem mudar no futuro.
Nota
Algumas partes do código de saída foram omitidas por motivos de clareza.
Descrição¶
Uma variável de registro é uma variável composta cujos componentes internos, chamados de campos, podem ter diferentes tipos de dados. O valor de uma variável de registro e os valores de seus campos podem mudar.
Você faz referência a uma variável de registro inteira pelo seu nome. Você faz referência a um campo de registro com a sintaxe record.field
.
Você pode criar uma variável de registro de qualquer uma dessas maneiras:
Defina um tipo de registro e, em seguida, declare uma variável desse tipo.
Use
%ROWTYPE
para declarar uma variável de registro que representa uma linha completa ou parcial de uma tabela ou visualização de banco de dados.Use
%TYPE
para declarar uma variável de registro do mesmo tipo que uma variável de registro declarada anteriormente.
(RECORD VARIABLES da referência de linguagem Oracle PL/SQL)
Para a conversão, a definição do tipo é substituída por um OBJECT Tipo de dados semiestruturados e, em seguida, seus usos são alterados de acordo com todas as operações.
Para definir um tipo de registro, a sintaxe é a seguinte:
type_definition := TYPE IS RECORD ( field_definition [, field_definition...] );
field_definition := field_name datatype [ { [NOT NULL default ] | default } ]
default := [ { := | DEFAULT } expression]
Para declarar uma variável desse tipo:
variable_name { record_type
| rowtype_attribute
| record_variable%TYPE
};
Amostra de padrões da origem¶
Nota
Algumas partes do código de saída foram omitidas por motivos de clareza.
Inicialização e atribuição de registros¶
Esse exemplo tenta inserir duas novas linhas usando uma variável de registro que é reatribuída no meio do procedimento.
Oracle¶
CREATE TABLE record_table(col1 FLOAT, col2 INTEGER);
CREATE OR REPLACE PROCEDURE record_procedure
IS
TYPE record_typ IS RECORD(col1 INTEGER, col2 FLOAT);
record_variable record_typ := record_typ(1, 1.5);--initialization
BEGIN
INSERT INTO record_table(col1, col2)
VALUES (record_variable.col2, record_variable.col1);--usage
--reassignment of properties
record_variable.col1 := 2;
record_variable.col2 := 2.5;
INSERT INTO record_table(col1, col2)
VALUES (record_variable.col2, record_variable.col1);--usage
END;
CALL record_procedure();
SELECT * FROM record_table;
|COL1|COL2|
|----+----|
| 1.5| 1|
| 2.5| 2|
Snowflake¶
Observe como as reatribuições são substituídas por um OBJECT_INSERT que é atualizado se a coluna já existir, e como a cláusula VALUES é substituída por SELECT.
CREATE OR REPLACE TABLE record_table (col1 FLOAT,
col2 INTEGER)
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"oracle"}}'
;
CREATE OR REPLACE PROCEDURE record_procedure ()
RETURNS VARCHAR
LANGUAGE SQL
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"oracle"}}'
EXECUTE AS CALLER
AS
$$
DECLARE
!!!RESOLVE EWI!!! /*** SSC-EWI-0056 - CUSTOM TYPES ARE NOT SUPPORTED IN SNOWFLAKE BUT REFERENCES TO THIS CUSTOM TYPE WERE CHANGED TO OBJECT ***/!!!
TYPE record_typ IS RECORD(col1 INTEGER, col2 FLOAT);
record_variable OBJECT !!!RESOLVE EWI!!! /*** SSC-EWI-0036 - record_typ DATA TYPE CONVERTED TO OBJECT ***/!!! := OBJECT_CONSTRUCT('COL1', 1, 'COL2', 1.5);--initialization
BEGIN
INSERT INTO record_table(col1, col2)
SELECT
:record_variable:COL2,
:record_variable:COL1;--usage
--reassignment of properties
record_variable := OBJECT_INSERT(record_variable, 'COL1', 2, true);
record_variable := OBJECT_INSERT(record_variable, 'COL2', 2.5, true);
INSERT INTO record_table(col1, col2)
SELECT
:record_variable:COL2,
:record_variable:COL1;--usage
END;
$$;
CALL record_procedure();
SELECT * FROM
record_table;
COL1|COL2|
----+----+
1.5| 1|
2.5| 2|
Registro de %ROWTYPE e registro de valores¶
Como as operações são as que definem a estrutura, essas definições podem ser substituídas por um tipo de dados OBJECT, mas os valores do registro precisam ser decompostos, pois não há suporte para a inserção do registro «como está».
Oracle¶
CREATE TABLE record_table(col1 INTEGER, col2 VARCHAR2(50), col3 DATE);
CREATE OR REPLACE PROCEDURE insert_record
IS
record_variable record_table%ROWTYPE;
BEGIN
record_variable.col1 := 1;
record_variable.col2 := 'Hello';
record_variable.col3 := DATE '2020-12-25';
INSERT INTO record_table VALUES record_variable;
END;
CALL insert_record();
SELECT * FROM record_table;
|COL1| COL2| COL3|
|----+-------|---------|
| 1|"Hello"|25-DEC-20|
Snowflake¶
Por fim, observe como a variável OBJECT precisa ser inicializada para que as informações sejam adicionadas a ela.
CREATE OR REPLACE TABLE record_table (col1 INTEGER,
col2 VARCHAR(50),
col3 TIMESTAMP /*** SSC-FDM-OR0042 - DATE TYPE COLUMN HAS A DIFFERENT BEHAVIOR IN SNOWFLAKE. ***/
)
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},"attributes":{"component":"oracle"}}'
;
CREATE OR REPLACE PROCEDURE insert_record ()
RETURNS VARCHAR
LANGUAGE SQL
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},"attributes":{"component":"oracle"}}'
EXECUTE AS CALLER
AS
$$
DECLARE
record_variable OBJECT !!!RESOLVE EWI!!! /*** SSC-EWI-0036 - ROWTYPE DATA TYPE CONVERTED TO OBJECT ***/!!! := OBJECT_CONSTRUCT();
BEGIN
record_variable := OBJECT_INSERT(record_variable, 'COL1', 1, true);
record_variable := OBJECT_INSERT(record_variable, 'COL2', 'Hello', true);
record_variable := OBJECT_INSERT(record_variable, 'COL3', DATE '2020-12-25', true);
INSERT INTO record_table
SELECT
:record_variable:COL1,
:record_variable:COL2,
:record_variable:COL3;
END;
$$;
CALL insert_record();
SELECT * FROM
record_table;
|COL1| COL2| COL3|
|----+-------|---------|
| 1|"Hello"|25-DEC-20|
Obtenção de dados em um registro¶
Oracle¶
CREATE TABLE record_table(col1 INTEGER, col2 VARCHAR2(50), col3 DATE);
INSERT INTO record_table(col1, col2 , col3)
VALUES (1, 'Hello', DATE '2020-12-25');
CREATE OR REPLACE PROCEDURE load_cursor_record
IS
CURSOR record_cursor IS
SELECT *
FROM record_table;
record_variable record_cursor%ROWTYPE;
BEGIN
OPEN record_cursor;
LOOP
FETCH record_cursor INTO record_variable;
EXIT WHEN record_cursor%NOTFOUND;
DBMS_OUTPUT.PUT_LINE(record_variable.col1);
DBMS_OUTPUT.PUT_LINE(record_variable.col2);
DBMS_OUTPUT.PUT_LINE(record_variable.col3);
END LOOP;
CLOSE record_cursor;
END;
CALL load_cursor_record();
DBMS OUTPUT
-----------
1
Hello
25-DEC-20
Snowflake¶
Observe o OBJECT_CONSTRUCT adicional na definição do Cursor, pois é isso que permite extrair um OBJECT, que pode ser usado para migrar sem problemas a instrução FETCH.
CREATE OR REPLACE TABLE record_table (col1 INTEGER,
col2 VARCHAR(50),
col3 TIMESTAMP /*** SSC-FDM-OR0042 - DATE TYPE COLUMN HAS A DIFFERENT BEHAVIOR IN SNOWFLAKE. ***/
)
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},"attributes":{"component":"oracle"}}'
;
INSERT INTO record_table(col1, col2 , col3)
VALUES (1, 'Hello', DATE '2020-12-25');
CREATE OR REPLACE PROCEDURE load_cursor_record ()
RETURNS VARCHAR
LANGUAGE SQL
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},"attributes":{"component":"oracle"}}'
EXECUTE AS CALLER
AS
$$
DECLARE
record_cursor CURSOR
FOR
SELECT
OBJECT_CONSTRUCT( *) sc_cursor_record
FROM
record_table;
record_variable OBJECT !!!RESOLVE EWI!!! /*** SSC-EWI-0036 - ROWTYPE DATA TYPE CONVERTED TO OBJECT ***/!!! := OBJECT_CONSTRUCT();
BEGIN
OPEN record_cursor;
LOOP
--** SSC-PRF-0003 - FETCH INSIDE A LOOP IS CONSIDERED A COMPLEX PATTERN, THIS COULD DEGRADE SNOWFLAKE PERFORMANCE. **
FETCH record_cursor INTO
:record_variable;
IF (record_variable IS NULL) THEN
EXIT;
END IF;
--** SSC-FDM-OR0035 - CHECK UDF IMPLEMENTATION FOR DBMS_OUTPUT.PUT_LINE_UDF. **
CALL DBMS_OUTPUT.PUT_LINE_UDF(:record_variable:COL1);
--** SSC-FDM-OR0035 - CHECK UDF IMPLEMENTATION FOR DBMS_OUTPUT.PUT_LINE_UDF. **
CALL DBMS_OUTPUT.PUT_LINE_UDF(:record_variable:COL2);
--** SSC-FDM-OR0035 - CHECK UDF IMPLEMENTATION FOR DBMS_OUTPUT.PUT_LINE_UDF. **
CALL DBMS_OUTPUT.PUT_LINE_UDF(:record_variable:COL3::DATE);
END LOOP;
CLOSE record_cursor;
END;
$$;
CALL load_cursor_record();
DBMS OUTPUT
-----------
1
Hello
25-DEC-20
Atribuição de uma variável de registro em uma SELECT INTO¶
Essa transformação consiste em aproveitar a função OBJECT_CONTRUCT para inicializar o registro usando as colunas SELECT como argumentos.
Exemplo de código auxiliar¶
create table sample_table(ID number, NAME varchar2(23));
CREATE TABLE RESULTS (COL1 VARCHAR(20), COL2 VARCHAR(40));
insert into sample_table values(1, 'NAME 1');
insert into sample_table values(2, 'NAME 2');
insert into sample_table values(3, 'NAME 3');
insert into sample_table values(4, 'NAME 4');
CREATE OR REPLACE TABLE sample_table (ID NUMBER(38, 18) /*** SSC-FDM-0006 - NUMBER TYPE COLUMN MAY NOT BEHAVE SIMILARLY IN SNOWFLAKE. ***/,
NAME VARCHAR(23))
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"oracle"}}'
;
CREATE OR REPLACE TABLE RESULTS (COL1 VARCHAR(20),
COL2 VARCHAR(40))
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"oracle"}}'
;
insert into sample_table
values(1, 'NAME 1');
insert into sample_table
values(2, 'NAME 2');
insert into sample_table
values(3, 'NAME 3');
insert into sample_table
values(4, 'NAME 4');
Oracle¶
CREATE OR REPLACE PROCEDURE sp_sample1 AS
-- Rowtype variable
rowtype_variable sample_table%rowtype;
--Record variable
TYPE record_typ_def IS RECORD(ID number, NAME varchar2(23));
record_variable_def record_typ_def;
-- Auxiliary variable
name_var VARCHAR(20);
BEGIN
SELECT * INTO rowtype_variable FROM sample_table WHERE ID = 1 FETCH NEXT 1 ROWS ONLY;
name_var := rowtype_variable.NAME;
INSERT INTO RESULTS(COL1, COL2) VALUES('SELECT 1', name_var);
SELECT ID, NAME INTO rowtype_variable FROM sample_table WHERE ID = 2 FETCH NEXT 1 ROWS ONLY;
name_var := rowtype_variable.NAME;
INSERT INTO RESULTS(COL1, COL2) VALUES('SELECT 2', name_var);
SELECT * INTO record_variable_def FROM sample_table WHERE ID = 3 FETCH NEXT 1 ROWS ONLY;
name_var := record_variable_def.NAME;
INSERT INTO RESULTS(COL1, COL2) VALUES('SELECT 3', name_var);
SELECT ID, NAME INTO record_variable_def FROM sample_table WHERE ID = 4 FETCH NEXT 1 ROWS ONLY;
name_var := record_variable_def.NAME;
INSERT INTO RESULTS(COL1, COL2) VALUES('SELECT 4', name_var);
END;
call sp_sample1();
SELECT * FROM results;
|COL1 |COL2 |
|--------|------|
|SELECT 1|NAME 1|
|SELECT 2|NAME 2|
|SELECT 3|NAME 3|
|SELECT 4|NAME 4|
Snowflake¶
CREATE OR REPLACE PROCEDURE sp_sample1 ()
RETURNS VARCHAR
LANGUAGE SQL
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"oracle"}}'
EXECUTE AS CALLER
AS
$$
DECLARE
-- Rowtype variable
rowtype_variable OBJECT !!!RESOLVE EWI!!! /*** SSC-EWI-0036 - ROWTYPE DATA TYPE CONVERTED TO OBJECT ***/!!! := OBJECT_CONSTRUCT();
--Record variable
!!!RESOLVE EWI!!! /*** SSC-EWI-0056 - CUSTOM TYPES ARE NOT SUPPORTED IN SNOWFLAKE BUT REFERENCES TO THIS CUSTOM TYPE WERE CHANGED TO OBJECT ***/!!!
TYPE record_typ_def IS RECORD(ID number, NAME varchar2(23));
record_variable_def OBJECT !!!RESOLVE EWI!!! /*** SSC-EWI-0036 - record_typ_def DATA TYPE CONVERTED TO OBJECT ***/!!! := OBJECT_CONSTRUCT();
-- Auxiliary variable
name_var VARCHAR(20);
BEGIN
SELECT
OBJECT_CONSTRUCT( *) INTO
:rowtype_variable
FROM
sample_table
WHERE ID = 1
FETCH NEXT 1 ROWS ONLY;
name_var := :rowtype_variable:NAME;
INSERT INTO RESULTS(COL1, COL2) VALUES('SELECT 1', :name_var);
SELECT
OBJECT_CONSTRUCT()
INTO
:rowtype_variable
FROM
sample_table
WHERE ID = 2
FETCH NEXT 1 ROWS ONLY;
name_var := :rowtype_variable:NAME;
INSERT INTO RESULTS(COL1, COL2) VALUES('SELECT 2', :name_var);
SELECT
OBJECT_CONSTRUCT( *) INTO
:record_variable_def
FROM
sample_table
WHERE ID = 3
FETCH NEXT 1 ROWS ONLY;
name_var := :record_variable_def:NAME;
INSERT INTO RESULTS(COL1, COL2) VALUES('SELECT 3', :name_var);
SELECT
OBJECT_CONSTRUCT('ID', ID, 'NAME', NAME) INTO
:record_variable_def
FROM
sample_table
WHERE ID = 4
FETCH NEXT 1 ROWS ONLY;
name_var := :record_variable_def:NAME;
INSERT INTO RESULTS(COL1, COL2) VALUES('SELECT 4', :name_var);
END;
$$;
call sp_sample1();
SELECT * FROM
results;
|COL1 |COL2 |
|--------|------|
|SELECT 1|NAME 1|
|SELECT 2|NAME 2|
|SELECT 3|NAME 3|
|SELECT 4|NAME 4|
Problemas conhecidos¶
1. The following functionalities are currently not being converted:¶
Busca de dados em um registro.
Registros aninhados (registros dentro de registros).
Coleções dentro de registros.
EWIs relacionados¶
SSC-EWI-0036: Tipo de dados convertido em outro tipo de dados.
SSC-EWI-0056: Create Type não tem suporte
SSC-FDM-0006: A coluna de tipo de número pode não se comportar de forma semelhante no Snowflake.
SSC-FDM-OR0042: O tipo de data transformado em carimbo de data/hora tem um comportamento diferente.
SSC-FDM-OR0035: DBMS_OUTPUT.PUTLINE verifique a implementação de UDF.
SSC-PRF-0003: A busca dentro de um loop é considerada um padrão complexo, o que pode prejudicar o desempenho do Snowflake.
Definição do tipo Varray¶
Aviso
Esta seção é um trabalho em andamento, as informações podem mudar no futuro.
Nota
Esta seção é para a versão PL/SQL de Varrays; para a versão autônoma, consulte Definição de tipo de matriz.
Nota
Algumas partes do código de saída foram omitidas por motivos de clareza.
Descrição¶
Um varray (variable-size array) é um array cujo número de elementos pode variar de zero (vazio) até o tamanho máximo declarado.
Para acessar um elemento de uma variável varray, use a sintaxe variable_name(index)
. O limite inferior de index
é 1; o limite superior é o número atual de elementos. O limite superior muda à medida que você adiciona ou exclui elementos, mas não pode exceder o tamanho máximo. Quando você armazena e recupera um varray do banco de dados, seus índices e a ordem dos elementos permanecem estáveis.
(VARRAYS da referência de linguagem Oracle PL/SQL)
Para a conversão, a definição do tipo é substituída por um ARRAY Tipo de dados semiestruturados e, em seguida, seus usos são alterados de acordo com todas as operações. Observe como a conversão para tabelas aninhadas e Varrays é a mesma.
Para definir um tipo de varray, a sintaxe é a seguinte:
type_definition := { VARRAY | [VARYING] ARRAY } (size_limit) OF datatype
[NOT NULL];
Para declarar uma variável desse tipo:
variable_name collection_type;
Amostra de padrões da origem¶
Definições de varray¶
Isso ilustra três maneiras diferentes de criar um varray e como migrar essas definições para as variáveis.
Oracle¶
CREATE OR REPLACE PROCEDURE associative_array_procedure
IS
TYPE varray_typ IS ARRAY(10) OF INTEGER;
TYPE varray_typ2 IS VARRAY(10) OF INTEGER;
TYPE varray_typ3 IS VARYING ARRAY(10) OF INTEGER;
array_variable varray_typ;
array_variable2 varray_typ2;
array_variable3 varray_typ3;
BEGIN
NULL;
END;
Snowflake¶
CREATE OR REPLACE PROCEDURE associative_array_procedure ()
RETURNS VARCHAR
LANGUAGE SQL
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},"attributes":{"component":"oracle"}}'
EXECUTE AS CALLER
AS
$$
DECLARE
-- !!!RESOLVE EWI!!! /*** SSC-EWI-0058 - FUNCTIONALITY FOR 'PL COLLECTION TYPE DEFINITION' IS NOT CURRENTLY SUPPORTED BY SNOWFLAKE SCRIPTING ***/!!!
-- TYPE varray_typ IS ARRAY(10) OF INTEGER;
-- !!!RESOLVE EWI!!! /*** SSC-EWI-0058 - FUNCTIONALITY FOR 'PL COLLECTION TYPE DEFINITION' IS NOT CURRENTLY SUPPORTED BY SNOWFLAKE SCRIPTING ***/!!!
-- TYPE varray_typ2 IS VARRAY(10) OF INTEGER;
-- !!!RESOLVE EWI!!! /*** SSC-EWI-0058 - FUNCTIONALITY FOR 'PL COLLECTION TYPE DEFINITION' IS NOT CURRENTLY SUPPORTED BY SNOWFLAKE SCRIPTING ***/!!!
-- TYPE varray_typ3 IS VARYING ARRAY(10) OF INTEGER;
array_variable VARIANT !!!RESOLVE EWI!!! /*** SSC-EWI-0062 - CUSTOM TYPE 'varray_typ' USAGE CHANGED TO VARIANT ***/!!!;
array_variable2 VARIANT !!!RESOLVE EWI!!! /*** SSC-EWI-0062 - CUSTOM TYPE 'varray_typ2' USAGE CHANGED TO VARIANT ***/!!!;
array_variable3 VARIANT !!!RESOLVE EWI!!! /*** SSC-EWI-0062 - CUSTOM TYPE 'varray_typ3' USAGE CHANGED TO VARIANT ***/!!!;
BEGIN
NULL;
END;
$$;
Iteração de varray¶
Oracle¶
CREATE OR REPLACE PROCEDURE varray_iteration
IS
TYPE varray_typ IS VARRAY(3) OF INTEGER;
varray_variable varray_typ := varray_typ(10, 20, 30);
BEGIN
FOR i IN 1..varray_variable.COUNT
LOOP
DBMS_OUTPUT.PUT_LINE(varray_variable(i));
END LOOP;
varray_variable(1) := 40;
FOR i IN 1..varray_variable.COUNT
LOOP
DBMS_OUTPUT.PUT_LINE(varray_variable(i));
END LOOP;
END;
/
CALL varray_iteration();
DBMS OUTPUT
-----------
10
20
30
40
20
30
Snowflake¶
Nota
Observe que um UDF foi adicionado para implementar a funcionalidade de atualização do elemento.
Este UDF será adicionado em revisões posteriores.
CREATE OR REPLACE PROCEDURE varray_iteration ()
RETURNS VARCHAR
LANGUAGE SQL
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},"attributes":{"component":"oracle"}}'
EXECUTE AS CALLER
AS
$$
DECLARE
-- !!!RESOLVE EWI!!! /*** SSC-EWI-0058 - FUNCTIONALITY FOR 'PL COLLECTION TYPE DEFINITION' IS NOT CURRENTLY SUPPORTED BY SNOWFLAKE SCRIPTING ***/!!!
-- TYPE varray_typ IS VARRAY(3) OF INTEGER;
varray_variable VARIANT !!!RESOLVE EWI!!! /*** SSC-EWI-0062 - CUSTOM TYPE 'varray_typ' USAGE CHANGED TO VARIANT ***/!!! := varray_typ(10, 20, 30);
BEGIN
FOR i IN 1 TO 0 /*varray_variable.COUNT*/!!!RESOLVE EWI!!! /*** SSC-EWI-0073 - PENDING FUNCTIONAL EQUIVALENCE REVIEW FOR 'VARRAY CUSTOM TYPE EXPRESSION' NODE ***/!!! LOOP
--** SSC-FDM-OR0035 - CHECK UDF IMPLEMENTATION FOR DBMS_OUTPUT.PUT_LINE_UDF. **
CALL DBMS_OUTPUT.PUT_LINE_UDF(varray_variable(i));
END LOOP;
!!!RESOLVE EWI!!! /*** SSC-EWI-OR0108 - THE FOLLOWING ASSIGNMENT STATEMENT IS NOT SUPPORTED BY SNOWFLAKE SCRIPTING ***/!!!
varray_variable(1) := 40;
FOR i IN 1 TO 0 /*varray_variable.COUNT*/!!!RESOLVE EWI!!! /*** SSC-EWI-0073 - PENDING FUNCTIONAL EQUIVALENCE REVIEW FOR 'VARRAY CUSTOM TYPE EXPRESSION' NODE ***/!!! LOOP
--** SSC-FDM-OR0035 - CHECK UDF IMPLEMENTATION FOR DBMS_OUTPUT.PUT_LINE_UDF. **
CALL DBMS_OUTPUT.PUT_LINE_UDF(varray_variable(i));
END LOOP;
END;
$$;
CALL varray_iteration();
CREATE OR REPLACE FUNCTION PUBLIC.INSERT_REPLACE_COLLECTION_ELEMENT_UDF(varray ARRAY, position INTEGER, newValue VARIANT)
RETURNS ARRAY
LANGUAGE SQL
AS
$$
ARRAY_CAT(
ARRAY_APPEND(ARRAY_SLICE(varray, 0, (position)-1), newValue),
ARRAY_SLICE(varray, position, ARRAY_SIZE(varray)))
$$;
DBMS OUTPUT
-----------
10
20
30
40
20
30
Problemas conhecidos¶
1. They are currently not being converted¶
O SnowConvert não suporta a conversão desses elementos.
2. Indexing needs to be modified¶
Os índices do Oracle começam em 1; no Snowflake, eles começarão em 0.
3. Array Density may not match the original¶
Como o tipo de dados ARRAY pode se tornar esparso, é preciso ter cuidado ao fazer adições ou exclusões da matriz. Usar ARRAY_COMPACT() após essas operações pode ser útil se a densidade for uma preocupação.
EWIs relacionados¶
SSC-EWI-0058: No momento, a funcionalidade não é compatível com o Snowflake Scripting.
SSC-EWI-0062: O uso do tipo personalizado foi alterado para variante.
SSC-EWI-0073: Revisão de equivalência funcional pendente.
SSC-EWI-OR0108: A seguinte instrução de atribuição não é compatível com o Snowflake Scripting.
SSC-FDM-OR0035: DBMS_OUTPUT.PUTLINE verifique a implementação de UDF.
Operações de coleta em massa¶
Aviso
Esta seção é um trabalho em andamento, as informações podem mudar no futuro
Nota
Algumas partes do código de saída foram omitidas por motivos de clareza.
Descrição¶
A cláusula BULK
COLLECT
, um recurso de SQL em massa, retorna resultados SQL para PL/SQL em lotes, em vez de um de cada vez.
A cláusula BULK
COLLECT
pode aparecer em:
Instrução
SELECT``INTO
Instrução
FETCH
Cláusu
RETURNING
INTO
de:Instrução
DELETE
Instrução
INSERT
Instrução
UPDATE
Instrução
EXECUTE``IMMEDIATE
Com a cláusula BULK
COLLECT
, cada uma das instruções anteriores recupera um conjunto de resultados inteiro e o armazena em uma ou mais variáveis de coleção em uma única operação (o que é mais eficiente do que usar uma instrução de loop para recuperar uma linha de resultado por vez).
(BULK COLLECT CLAUSE da referência de linguagem Oracle PL/SQL)
Esta seção apresenta algumas soluções alternativas para SELECTs e cursor FETCH com cláusulas em massa.
Amostra de padrões da origem¶
Tabela de origem¶
Oracle¶
CREATE TABLE bulk_collect_table(col1 INTEGER);
INSERT INTO bulk_collect_table VALUES(1);
INSERT INTO bulk_collect_table VALUES(2);
INSERT INTO bulk_collect_table VALUES(3);
INSERT INTO bulk_collect_table VALUES(4);
INSERT INTO bulk_collect_table VALUES(5);
INSERT INTO bulk_collect_table VALUES(6);
Snowflake¶
CREATE OR REPLACE TABLE bulk_collect_table (col1 INTEGER)
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"oracle"}}'
;
INSERT INTO bulk_collect_table
VALUES(1);
INSERT INTO bulk_collect_table
VALUES(2);
INSERT INTO bulk_collect_table
VALUES(3);
INSERT INTO bulk_collect_table
VALUES(4);
INSERT INTO bulk_collect_table
VALUES(5);
INSERT INTO bulk_collect_table
VALUES(6);
Coleta em massa de uma tabela¶
Oracle¶
CREATE OR REPLACE PROCEDURE bulk_collect_procedure
IS
CURSOR record_cursor IS
SELECT *
FROM bulk_collect_table;
TYPE fetch_collection_typ IS TABLE OF record_cursor%ROWTYPE;
fetch_collection_variable fetch_collection_typ;
TYPE collection_typ IS TABLE OF bulk_collect_table%ROWTYPE;
collection_variable collection_typ;
BEGIN
SELECT * BULK COLLECT INTO collection_variable FROM bulk_collect_table;
FOR i IN 1..collection_variable.COUNT
LOOP
DBMS_OUTPUT.PUT_LINE(collection_variable(i).col1);
END LOOP;
collection_variable := null;
OPEN record_cursor;
FETCH record_cursor BULK COLLECT INTO collection_variable;
CLOSE record_cursor;
FOR i IN 1..collection_variable.COUNT
LOOP
DBMS_OUTPUT.PUT_LINE(collection_variable(i).col1+6);
END LOOP;
collection_variable := null;
EXECUTE IMMEDIATE 'SELECT * FROM bulk_collect_table' BULK COLLECT INTO collection_variable;
FOR i IN 1..collection_variable.COUNT
LOOP
DBMS_OUTPUT.PUT_LINE(collection_variable(i).col1+12);
END LOOP;
END;
/
CALL bulk_collect_procedure();
DBMS OUTPUT
-----------
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
Snowflake¶
EXECUTE IMMEDIATE com a cláusula Bulk Collect não tem soluções alternativas oferecidas.
Nota
Observe que, embora o cursor FETCH possa ser preservado em sua maior parte, é recomendável que seja alterado para instruções SELECT sempre que possível por questões de desempenho.
CREATE OR REPLACE PROCEDURE bulk_collect_procedure ()
RETURNS VARCHAR
LANGUAGE SQL
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},"attributes":{"component":"oracle"}}'
EXECUTE AS CALLER
AS
$$
DECLARE
record_cursor CURSOR
FOR
SELECT *
FROM
bulk_collect_table;
-- !!!RESOLVE EWI!!! /*** SSC-EWI-0058 - FUNCTIONALITY FOR 'PL COLLECTION TYPE DEFINITION' IS NOT CURRENTLY SUPPORTED BY SNOWFLAKE SCRIPTING ***/!!!
-- TYPE fetch_collection_typ IS TABLE OF record_cursor%ROWTYPE;
fetch_collection_variable VARIANT !!!RESOLVE EWI!!! /*** SSC-EWI-0062 - CUSTOM TYPE 'fetch_collection_typ' USAGE CHANGED TO VARIANT ***/!!!;
-- !!!RESOLVE EWI!!! /*** SSC-EWI-0058 - FUNCTIONALITY FOR 'PL COLLECTION TYPE DEFINITION' IS NOT CURRENTLY SUPPORTED BY SNOWFLAKE SCRIPTING ***/!!!
-- TYPE collection_typ IS TABLE OF bulk_collect_table%ROWTYPE;
collection_variable VARIANT !!!RESOLVE EWI!!! /*** SSC-EWI-0062 - CUSTOM TYPE 'collection_typ' USAGE CHANGED TO VARIANT ***/!!!;
BEGIN
!!!RESOLVE EWI!!! /*** SSC-EWI-0058 - FUNCTIONALITY FOR 'RECORDS AND COLLECTIONS' IS NOT CURRENTLY SUPPORTED BY SNOWFLAKE SCRIPTING ***/!!!
SELECT * BULK COLLECT INTO collection_variable FROM bulk_collect_table;
FOR i IN 1 TO 0 /*collection_variable.COUNT*/!!!RESOLVE EWI!!! /*** SSC-EWI-0073 - PENDING FUNCTIONAL EQUIVALENCE REVIEW FOR 'NESTED TABLE CUSTOM TYPE EXPRESSION' NODE ***/!!! LOOP
--** SSC-FDM-OR0035 - CHECK UDF IMPLEMENTATION FOR DBMS_OUTPUT.PUT_LINE_UDF. **
CALL DBMS_OUTPUT.PUT_LINE_UDF(:collection_variable(i).col1);
END LOOP;
!!!RESOLVE EWI!!! /*** SSC-EWI-OR0108 - THE FOLLOWING ASSIGNMENT STATEMENT IS NOT SUPPORTED BY SNOWFLAKE SCRIPTING ***/!!!
collection_variable := null;
OPEN record_cursor;
--** SSC-PRF-0001 - THIS STATEMENT HAS USAGES OF CURSOR FETCH BULK OPERATIONS **
record_cursor := (
CALL FETCH_BULK_COLLECTION_RECORDS_UDF(:record_cursor)
);
collection_variable := :record_cursor:RESULT;
CLOSE record_cursor;
FOR i IN 1 TO 0 /*collection_variable.COUNT*/!!!RESOLVE EWI!!! /*** SSC-EWI-0073 - PENDING FUNCTIONAL EQUIVALENCE REVIEW FOR 'NESTED TABLE CUSTOM TYPE EXPRESSION' NODE ***/!!! LOOP
--** SSC-FDM-OR0035 - CHECK UDF IMPLEMENTATION FOR DBMS_OUTPUT.PUT_LINE_UDF. **
CALL DBMS_OUTPUT.PUT_LINE_UDF(
!!!RESOLVE EWI!!! /*** SSC-EWI-OR0036 - TYPES RESOLUTION ISSUES, ARITHMETIC OPERATION '+' MAY NOT BEHAVE CORRECTLY BETWEEN unknown AND Number ***/!!!
:collection_variable(i).col1+6);
END LOOP;
!!!RESOLVE EWI!!! /*** SSC-EWI-OR0108 - THE FOLLOWING ASSIGNMENT STATEMENT IS NOT SUPPORTED BY SNOWFLAKE SCRIPTING ***/!!!
collection_variable := null;
!!!RESOLVE EWI!!! /*** SSC-EWI-0030 - THE STATEMENT BELOW HAS USAGES OF DYNAMIC SQL. ***/!!!
EXECUTE IMMEDIATE 'SELECT * FROM
bulk_collect_table'
!!!RESOLVE EWI!!! /*** SSC-EWI-0058 - FUNCTIONALITY FOR 'EXECUTE IMMEDIATE RETURNING CLAUSE' IS NOT CURRENTLY SUPPORTED BY SNOWFLAKE SCRIPTING ***/!!!
BULK COLLECT INTO collection_variable;
FOR i IN 1 TO 0 /*collection_variable.COUNT*/!!!RESOLVE EWI!!! /*** SSC-EWI-0073 - PENDING FUNCTIONAL EQUIVALENCE REVIEW FOR 'NESTED TABLE CUSTOM TYPE EXPRESSION' NODE ***/!!! LOOP
--** SSC-FDM-OR0035 - CHECK UDF IMPLEMENTATION FOR DBMS_OUTPUT.PUT_LINE_UDF. **
CALL DBMS_OUTPUT.PUT_LINE_UDF(
!!!RESOLVE EWI!!! /*** SSC-EWI-OR0036 - TYPES RESOLUTION ISSUES, ARITHMETIC OPERATION '+' MAY NOT BEHAVE CORRECTLY BETWEEN unknown AND Number ***/!!!
:collection_variable(i).col1+12);
END LOOP;
END;
$$;
CALL bulk_collect_procedure();
DBMS OUTPUT
-----------
1
2
3
4
5
6
7
8
9
10
11
-- EXECUTE IMMEDIATE NOT EXECUTED, it's not supported
Caso de instrução SELECT INTO¶
Nesse caso, a especificação de conversão usa RESULTSETs. Consulte a documentação das instruções WITH, SELECT e BULK COLLECT INTO aqui:
Problemas conhecidos¶
1. Heavy performance issues on FETCH Cursor workaround¶
A solução alternativa para o cursor Fetch tem grandes requisitos de desempenho devido à tabela Temporary. É recomendável que eles sejam migrados manualmente para instruções SELECT
2. Execute immediate statements are not transformed¶
Elas não são compatíveis com o SnowConvert, mas podem ser alteradas manualmente para instruções SELECT.
EWIs relacionados¶
SSC-EWI-0058: No momento, a funcionalidade não é compatível com o Snowflake Scripting.
SSC-EWI-0062: O uso do tipo personalizado foi alterado para variante.
SSC-EWI-0073: Revisão de equivalência funcional pendente
SSC-EWI-OR0036: Problemas de resolução de tipos, a operação aritmética pode não se comportar corretamente entre string e date.
SSC-EWI-OR0108: A seguinte instrução de atribuição não é compatível com o Snowflake Scripting.
SSC-FDM-OR0035: DBMS_OUTPUT.PUTLINE verifique a implementação de UDF.
SSC-PRF-0001: Essa instrução tem usos de operações em massa de busca de cursor.
SSC-EWI-0030: A instrução abaixo tem usos de SQL dinâmico
Instruções WITH, SELECT e BULK COLLECT INTO¶
Esta seção é uma especificação de conversão. As informações podem mudar no futuro.
Nota
Algumas partes do código de saída foram omitidas por motivos de clareza.
Descrição¶
Esta seção é uma especificação de conversão para a instrução WITH subsequente a uma instrução SELECT que usa uma instrução BULK COLLECT INTO. Para obter mais informações, consulte a documentação a seguir:
Amostra de padrões da origem¶
Nota
Algumas partes do código de saída foram omitidas por motivos de clareza.
A consulta a seguir é usada para os exemplos a seguir.
-- Sample MySampleTable table
CREATE TABLE MySampleTable (
MySampleID NUMBER PRIMARY KEY,
FirstName VARCHAR2(50),
Salary NUMBER,
Department VARCHAR2(50)
);
-- Insert some sample data
INSERT INTO MySampleTable (MySampleID, FirstName, Salary, Department)
VALUES (1, 'Bob One', 50000, 'HR');
INSERT INTO MySampleTable (MySampleID, FirstName, Salary, Department)
VALUES (2, 'Bob Two', 60000, 'HR');
INSERT INTO MySampleTable (MySampleID, FirstName, Salary, Department)
VALUES (3, 'Bob Three', 75000, 'IT');
INSERT INTO MySampleTable (MySampleID, FirstName, Salary, Department)
VALUES (4, 'Bob Four', 80000, 'IT');
-- Sample MySampleTable table
CREATE OR REPLACE TABLE MySampleTable (
MySampleID NUMBER(38, 18) /*** SSC-FDM-0006 - NUMBER TYPE COLUMN MAY NOT BEHAVE SIMILARLY IN SNOWFLAKE. ***/ PRIMARY KEY,
FirstName VARCHAR(50),
Salary NUMBER(38, 18) /*** SSC-FDM-0006 - NUMBER TYPE COLUMN MAY NOT BEHAVE SIMILARLY IN SNOWFLAKE. ***/,
Department VARCHAR(50)
)
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"oracle"}}'
;
-- Insert some sample data
INSERT INTO MySampleTable(MySampleID, FirstName, Salary, Department)
VALUES (1, 'Bob One', 50000, 'HR');
INSERT INTO MySampleTable(MySampleID, FirstName, Salary, Department)
VALUES (2, 'Bob Two', 60000, 'HR');
INSERT INTO MySampleTable(MySampleID, FirstName, Salary, Department)
VALUES (3, 'Bob Three', 75000, 'IT');
INSERT INTO MySampleTable(MySampleID, FirstName, Salary, Department)
VALUES (4, 'Bob Four', 80000, 'IT');
1. Inside procedure simple case¶
Essa é uma abordagem que usa um tipo de dados de conjunto de resultados. Os tipos definidos pelo usuário devem ser revisados. Consulte a seguinte documentação do Snowflake para obter mais informações sobre RESULTSETs.
O exemplo a seguir usa um tipo definido pelo usuário e é declarado indiretamente como uma tabela. A conversão para esse caso implementa um RESULTSET como um tipo de dados no Snowflake. O conjunto de resultados é armazenado em uma variável que deve ser retornada em uma função TABLE()
.
Oracle
-- Additional Params: -t JavaScript
CREATE OR REPLACE PROCEDURE simple_procedure
IS
TYPE salary_collection IS TABLE OF NUMBER;
v_salaries salary_collection := salary_collection();
BEGIN
WITH IT_Employees AS (
SELECT Salary
FROM MySampleTable
WHERE Department = 'IT'
)
SELECT Salary BULK COLLECT INTO v_salaries
FROM IT_Employees;
END;
CALL simple_procedure();
Nota
A consulta não retorna resultados, mas as informações coletadas esperadas seriam as IT Salary Information usadas no exemplo:
IT_Salary |
---|
75000 |
80000 |
Uma das limitações de RESULTSETs é que ele não pode ser usado como tabela. Por exemplo: select * from my_result_set;
(Isso é um erro, consulte a documentação a seguir para obter mais informações).
Snowflake Scripting
CREATE OR REPLACE PROCEDURE simple_procedure ()
RETURNS STRING
LANGUAGE JAVASCRIPT
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"oracle"}}'
EXECUTE AS CALLER
AS
$$
// SnowConvert Helpers Code section is omitted.
/* ** SSC-EWI-OR0072 - PROCEDURAL MEMBER TYPE DEFINITION NOT SUPPORTED. ** */
/* TYPE salary_collection IS TABLE OF NUMBER */
;
/* ** SSC-EWI-OR0104 - UNUSABLE VARIABLE, ITS TYPE WAS NOT TRANSFORMED ** */
/* v_salaries salary_collection := salary_collection() */
;
// WITH IT_Employees AS (
// SELECT Salary
// FROM MySampleTable
// WHERE Department = 'IT'
// )
// SELECT Salary BULK COLLECT INTO v_salaries
// FROM IT_Employees
!!!RESOLVE EWI!!! /*** SSC-EWI-0073 - PENDING FUNCTIONAL EQUIVALENCE REVIEW FOR 'WithCte' NODE ***/!!!
null
$$;
CALL simple_procedure();
SALARY |
---|
77500 |
80000 |
2. Simple case for iterations: FOR LOOP statement
O caso a seguir é para definir uma conversão para iteração com FOR...LOOP
. Nesse caso, o tipo definido pelo usuário é implicitamente uma tabela, portanto, é possível usar um cursor para iterar. Consulte a documentação a seguir para saber mais:
Documentação do Snowflake sobre o retorno de uma tabela para um cursor
Nesse caso, é necessário criar um cursor para a iteração. Examine a seguinte documentação sobre a sintaxe de atribuição de cursor.
Oracle
CREATE OR REPLACE PROCEDURE simple_procedure
IS
TYPE salary_collection IS TABLE OF NUMBER;
v_salaries salary_collection := salary_collection();
v_average_salary NUMBER;
salaries_count NUMBER;
BEGIN
salaries_count := 0;
WITH IT_Employees AS (
SELECT Salary
FROM MySampleTable
WHERE Department = 'IT'
)
SELECT Salary BULK COLLECT INTO v_salaries
FROM IT_Employees;
-- Calculate the average salary
IF v_salaries.COUNT > 0 THEN
v_average_salary := 0;
FOR i IN 1..v_salaries.COUNT LOOP
v_average_salary := v_average_salary + v_salaries(i);
salaries_count := salaries_count + 1;
END LOOP;
v_average_salary := v_average_salary / salaries_count;
END IF;
-- Display the average salary
DBMS_OUTPUT.PUT_LINE('Average Salary for IT Department: ' || v_average_salary);
END;
/
CALL simple_procedure();
Statement processed.
Average Salary for IT Department: 77500
Snowflake Scripting
CREATE OR REPLACE PROCEDURE simple_procedure ()
RETURNS VARCHAR
LANGUAGE SQL
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},"attributes":{"component":"oracle"}}'
EXECUTE AS CALLER
AS
$$
DECLARE
-- !!!RESOLVE EWI!!! /*** SSC-EWI-0058 - FUNCTIONALITY FOR 'PL COLLECTION TYPE DEFINITION' IS NOT CURRENTLY SUPPORTED BY SNOWFLAKE SCRIPTING ***/!!!
-- TYPE salary_collection IS TABLE OF NUMBER;
v_salaries VARIANT !!!RESOLVE EWI!!! /*** SSC-EWI-0062 - CUSTOM TYPE 'salary_collection' USAGE CHANGED TO VARIANT ***/!!! := salary_collection();
v_average_salary NUMBER(38, 18);
salaries_count NUMBER(38, 18);
BEGIN
salaries_count := 0;
WITH IT_Employees AS
(
SELECT Salary
FROM
MySampleTable
WHERE Department = 'IT'
)
!!!RESOLVE EWI!!! /*** SSC-EWI-0058 - FUNCTIONALITY FOR 'RECORDS AND COLLECTIONS' IS NOT CURRENTLY SUPPORTED BY SNOWFLAKE SCRIPTING ***/!!!
SELECT Salary BULK COLLECT INTO v_salaries
FROM IT_Employees;
-- Calculate the average salary
IF (null /*v_salaries.COUNT*/!!!RESOLVE EWI!!! /*** SSC-EWI-0073 - PENDING FUNCTIONAL EQUIVALENCE REVIEW FOR 'NESTED TABLE CUSTOM TYPE EXPRESSION' NODE ***/!!! > 0) THEN
v_average_salary := 0;
FOR i IN 1 TO 0 /*v_salaries.COUNT*/!!!RESOLVE EWI!!! /*** SSC-EWI-0073 - PENDING FUNCTIONAL EQUIVALENCE REVIEW FOR 'NESTED TABLE CUSTOM TYPE EXPRESSION' NODE ***/!!! LOOP
v_average_salary :=
!!!RESOLVE EWI!!! /*** SSC-EWI-OR0036 - TYPES RESOLUTION ISSUES, ARITHMETIC OPERATION '+' MAY NOT BEHAVE CORRECTLY BETWEEN ExactNumeric AND salary_collection ***/!!!
:v_average_salary + v_salaries(i);
salaries_count := :salaries_count + 1;
END LOOP;
v_average_salary := :v_average_salary / :salaries_count;
END IF;
-- Display the average salary
--** SSC-FDM-OR0035 - CHECK UDF IMPLEMENTATION FOR DBMS_OUTPUT.PUT_LINE_UDF. **
CALL DBMS_OUTPUT.PUT_LINE_UDF('Average Salary for IT Department: ' || NVL(:v_average_salary :: STRING, ''));
END;
$$;
CALL simple_procedure();
SIMPLE_PROCEDURE |
---|
Average Salary for IT Department: 77500 |
Known Issues
1. Resulset limitations.
Há limitações ao usar o tipo de dados RESULTSET. Consulte a seguinte documentação do Snowflake para saber mais. As limitações marcantes são as seguintes:
A declaração de uma coluna do tipo RESULTSET.
A declaração de um parâmetro do tipo RESULTSET.
Declarando o tipo de retorno de um procedimento armazenado como um RESULTSET.
2. Execute statements with Bulk Collect clause are not supported.
Consulte a seguinte documentação.
Related EWIs
SSC-EWI-0058: No momento, a funcionalidade não é compatível com o Snowflake Scripting.
SSC-EWI-0062: O uso do tipo personalizado foi alterado para variante.
SSC-EWI-0073: Revisão de equivalência funcional pendente
SSC-EWI-OR0036: Problemas de resolução de tipos, a operação aritmética pode não se comportar corretamente entre string e date.
SSC-EWI-OR0072: Membro do procedimento não suportado
SSC-EWI-OR0104: Variável de coleção não utilizável.
SSC-FDM-0006: A coluna de tipo de número pode não se comportar de forma semelhante no Snowflake.
SSC-FDM-OR0035: DBMS_OUTPUT.PUTLINE verifique a implementação de UDF.
HELPERS
Auxiliares de cursor em massa
Nota
Talvez você também se interesse por Transformação Default FORALL.
O cursor é simulado com um OBJECT
com diferentes informações sobre o estado do cursor. Uma tabela temporária é criada para armazenar o conjunto de resultados da consulta do cursor.
A maioria desses Procedimentos retorna um novo Objeto com o estado atualizado do cursor.
INIT_CURSOR¶
Essa função inicializa um novo objeto com as informações básicas do cursor
CREATE OR REPLACE FUNCTION INIT_CURSOR(NAME VARCHAR, QUERY VARCHAR)
RETURNS OBJECT
AS
$$
SELECT OBJECT_CONSTRUCT('NAME', NAME, 'ROWCOUNT', -1, 'QUERY', QUERY, 'ISOPEN', FALSE, 'FOUND', NULL, 'NOTFOUND', NULL)
$$;
OPEN_BULK_CURSOR¶
Esses procedimentos criam uma tabela temporária com a consulta do cursor. Existe uma sobrecarga opcional para oferecer suporte a vinculações.
CREATE OR REPLACE PROCEDURE OPEN_BULK_CURSOR(CURSOR OBJECT, BINDINGS ARRAY)
RETURNS OBJECT
LANGUAGE JAVASCRIPT
EXECUTE AS CALLER
AS
$$
var query = `CREATE OR REPLACE TEMPORARY TABLE ${CURSOR.NAME}_TEMP_TABLE AS ${CURSOR.QUERY}`;
snowflake.execute({ sqlText: query, binds: BINDINGS });
CURSOR.ROWCOUNT = 0;
CURSOR.ISOPEN = true;
return CURSOR;
$$;
CREATE OR REPLACE PROCEDURE OPEN_BULK_CURSOR(CURSOR OBJECT)
RETURNS OBJECT
LANGUAGE SQL
EXECUTE AS CALLER
AS
$$
DECLARE
RESULT OBJECT;
BEGIN
RESULT := (CALL OPEN_BULK_CURSOR(:CURSOR, NULL));
RETURN :RESULT;
END;
$$;
CLOSE_BULK_CURSOR¶
Esse procedimento exclui a tabela temporária que armazenava o conjunto de resultados do cursor e redefine as propriedades do cursor para seu estado inicial.
CREATE OR REPLACE PROCEDURE CLOSE_BULK_CURSOR(CURSOR OBJECT)
RETURNS OBJECT
LANGUAGE JAVASCRIPT
EXECUTE AS CALLER
AS
$$
var query = `DROP TABLE ${CURSOR.NAME}_TEMP_TABLE`;
snowflake.execute({ sqlText: query });
CURSOR.ROWCOUNT = -1;
CURSOR.ISOPEN = false;
CURSOR.FOUND = null;
CURSOR.NOTFOUND = null;
return CURSOR;
$$;
Auxiliares FETCH¶
Como o Oracle é capaz de executar a instrução FETCH
em diferentes tipos de cenários, foram criados vários procedimentos com sobrecargas para lidar com cada caso. Esses auxiliares salvam os valores obtidos na propriedade RESULT
do objeto CURSOR
.
Algumas das sobrecargas incluem variações quando a cláusula LIMIT
foi usada ou não. Outras sobrecargas têm um argumento COLUMN_NAMES
que é necessário quando a instrução FETCH
está sendo feita em uma variável que tem ou contém registros com nomes de coluna diferentes dos nomes de coluna da consulta.
FETCH_BULK_COLLECTION_RECORDS¶
Esses procedimentos são usados quando um FETCH BULK
é feito em uma coleção de registros.
CREATE OR REPLACE PROCEDURE FETCH_BULK_COLLECTION_RECORDS(CURSOR OBJECT, LIMIT FLOAT, COLUMN_NAMES ARRAY)
RETURNS OBJECT
LANGUAGE JAVASCRIPT
EXECUTE AS CALLER
AS
$$
var objectConstructArgs = [];
if (COLUMN_NAMES) {
for (let i = 0 ; i < COLUMN_NAMES.length ; i++) {
objectConstructArgs.push("'" + COLUMN_NAMES[i] + "'");
objectConstructArgs.push('$' + (i + 1));
}
} else {
objectConstructArgs.push('*');
}
var limitValue = LIMIT ?? 'NULL';
var query = `SELECT ARRAY_AGG(OBJECT_CONSTRUCT(${objectConstructArgs.join(', ')})) FROM (SELECT * FROM ${CURSOR.NAME}_TEMP_TABLE LIMIT ${limitValue} OFFSET ${CURSOR.ROWCOUNT})`;
var stmt = snowflake.createStatement({ sqlText: query});
var resultSet = stmt.execute();
resultSet.next();
CURSOR.RESULT = resultSet.getColumnValue(1);
CURSOR.ROWCOUNT += CURSOR.RESULT.length;
CURSOR.FOUND = CURSOR.RESULT.length > 0;
CURSOR.NOTFOUND = !CURSOR.FOUND;
return CURSOR;
$$;
CREATE OR REPLACE PROCEDURE FETCH_BULK_COLLECTION_RECORDS(CURSOR OBJECT)
RETURNS OBJECT
LANGUAGE SQL
EXECUTE AS CALLER
AS
$$
DECLARE
RESULT OBJECT;
BEGIN
RESULT := (CALL FETCH_BULK_COLLECTION_RECORDS(:CURSOR, NULL, NULL));
RETURN :RESULT;
END;
$$;
CREATE OR REPLACE PROCEDURE FETCH_BULK_COLLECTION_RECORDS(CURSOR OBJECT, LIMIT INTEGER)
RETURNS OBJECT
LANGUAGE SQL
EXECUTE AS CALLER
AS
$$
DECLARE
RESULT OBJECT;
BEGIN
RESULT := (CALL FETCH_BULK_COLLECTION_RECORDS(:CURSOR, :LIMIT, NULL));
RETURN :RESULT;
END;
$$;
CREATE OR REPLACE PROCEDURE FETCH_BULK_COLLECTION_RECORDS(CURSOR OBJECT, COLUMN_NAMES ARRAY)
RETURNS OBJECT
LANGUAGE SQL
EXECUTE AS CALLER
AS
$$
DECLARE
RESULT OBJECT;
BEGIN
RESULT := (CALL FETCH_BULK_COLLECTION_RECORDS(:CURSOR, NULL, :COLUMN_NAMES));
RETURN :RESULT;
END;
$$;
FETCH_BULK_COLLECTIONS¶
Esses procedimentos são usados quando a instrução FETCH
é feita em uma ou várias coleções. Como as colunas são especificadas nessa operação FETCH
, não é necessária uma substituição para COLUMN_NAMES
específico.
CREATE OR REPLACE PROCEDURE FETCH_BULK_COLLECTIONS(CURSOR OBJECT, LIMIT FLOAT)
RETURNS OBJECT
LANGUAGE JAVASCRIPT
EXECUTE AS CALLER
AS
$$
var limitClause = '';
var limitValue = LIMIT ?? 'NULL';
var query = `SELECT * FROM ${CURSOR.NAME}_TEMP_TABLE LIMIT ${limitValue} OFFSET ${CURSOR.ROWCOUNT}`;
var stmt = snowflake.createStatement({ sqlText: query});
var resultSet = stmt.execute();
var column_count = stmt.getColumnCount();
CURSOR.RESULT = [];
for (let i = 0 ; i < column_count ; i++) {
CURSOR.RESULT[i] = [];
}
while (resultSet.next()) {
for (let i = 1 ; i <= column_count ; i++) {
let columnName = stmt.getColumnName(i);
CURSOR.RESULT[i - 1].push(resultSet.getColumnValue(columnName));
}
}
CURSOR.ROWCOUNT += stmt.getRowCount();
CURSOR.FOUND = stmt.getRowCount() > 0;
CURSOR.NOTFOUND = !CURSOR.FOUND;
return CURSOR;
$$;
CREATE OR REPLACE PROCEDURE FETCH_BULK_COLLECTIONS(CURSOR OBJECT)
RETURNS OBJECT
LANGUAGE SQL
EXECUTE AS CALLER
AS
$$
DECLARE
RESULT OBJECT;
BEGIN
RESULT := (CALL FETCH_BULK_COLLECTIONS(:CURSOR, NULL));
RETURN :RESULT;
END;
$$;
FETCH_BULK_RECORD_COLLECTIONS¶
Esses procedimentos são usados quando um FETCH BULK
é feito em um registro de coleções.
CREATE OR REPLACE PROCEDURE FETCH_BULK_RECORD_COLLECTIONS(CURSOR OBJECT, LIMIT FLOAT, COLUMN_NAMES ARRAY)
RETURNS OBJECT
LANGUAGE JAVASCRIPT
EXECUTE AS CALLER
AS
$$
var limitValue = LIMIT ?? 'NULL';
var query = `SELECT * FROM ${CURSOR.NAME}_TEMP_TABLE LIMIT ${limitValue} OFFSET ${CURSOR.ROWCOUNT}`;
var stmt = snowflake.createStatement({ sqlText: query});
var resultSet = stmt.execute();
var column_count = stmt.getColumnCount();
CURSOR.RESULT = {};
if (COLUMN_NAMES)
{
for (let i = 0 ; i < COLUMN_NAMES.length ; i++) {
CURSOR.RESULT[COLUMN_NAMES[i]] = [];
}
} else {
for (let i = 1 ; i <= column_count ; i++) {
let columnName = stmt.getColumnName(i);
CURSOR.RESULT[columnName] = [];
}
}
while (resultSet.next()) {
for (let i = 1 ; i <= column_count ; i++) {
let columnName = stmt.getColumnName(i);
let fieldName = COLUMN_NAMES ? COLUMN_NAMES[i - 1] : columnName;
CURSOR.RESULT[fieldName].push(resultSet.getColumnValue(columnName));
}
}
CURSOR.ROWCOUNT += stmt.getRowCount();
CURSOR.FOUND = stmt.getRowCount() > 0;
CURSOR.NOTFOUND = !CURSOR.FOUND;
return CURSOR;
$$;
CREATE OR REPLACE PROCEDURE FETCH_BULK_RECORD_COLLECTIONS(CURSOR OBJECT)
RETURNS OBJECT
LANGUAGE SQL
EXECUTE AS CALLER
AS
$$
DECLARE
RESULT OBJECT;
BEGIN
RESULT := (CALL FETCH_BULK_RECORD_COLLECTIONS(:CURSOR, NULL, NULL));
RETURN :RESULT;
END;
$$;
CREATE OR REPLACE PROCEDURE FETCH_BULK_RECORD_COLLECTIONS(CURSOR OBJECT, LIMIT INTEGER)
RETURNS OBJECT
LANGUAGE SQL
EXECUTE AS CALLER
AS
$$
DECLARE
RESULT OBJECT;
BEGIN
RESULT := (CALL FETCH_BULK_RECORD_COLLECTIONS(:CURSOR, :LIMIT, NULL));
RETURN :RESULT;
END;
$$;
CREATE OR REPLACE PROCEDURE FETCH_BULK_RECORD_COLLECTIONS(CURSOR OBJECT, COLUMN_NAMES ARRAY)
RETURNS OBJECT
LANGUAGE SQL
EXECUTE AS CALLER
AS
$$
DECLARE
RESULT OBJECT;
BEGIN
RESULT := (CALL FETCH_BULK_RECORD_COLLECTIONS(:CURSOR, NULL, :COLUMN_NAMES));
RETURN :RESULT;
END;
$$;