SnowConvert :PL/SQL vers Snowflake Scripting

ASSIGNMENT STATEMENT

Description

L’instruction d’affectation définit la valeur d’un élément de données dans une valeur valide.\ (Référence linguistique Oracle PL/SQL Instruction ASSIGNMENT)

Note

Certaines parties du code de sortie sont omises pour des raisons de clarté.

 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
}
Copy
 LET <variable_name> <type> { DEFAULT | := } <expression> ;

LET <variable_name> { DEFAULT | := } <expression> ;
Copy

Note

Le mot-clé LET n’est pas nécessaire pour les instructions d’affectation lorsque la variable a été déclarée auparavant. Consultez la documentation sur l’affectation Snowflake pour plus d’informations.

Modèles d’échantillons de sources

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;
Copy
COL1|COL2|COL3       |COL4|
----+----+-----------+----+
   1| 4.2|Hello World|   1|

Copy
Exécution de scripts 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;
Copy
COL1                |COL2                |COL3       |COL4|
--------------------+--------------------+-----------+----+
1.000000000000000000|4.000000000000000000|Hello World|1   |

Copy

Avertissement

La transformation de certains types de données doit être mise à jour, ce qui peut entraîner des résultats différents. Par exemple, NUMBER à NUMBER arrondit la valeur et le point décimal est perdu. Cette question fait déjà l’objet d’un document de travail.

2. Out Parameter Assignment

Pour obtenir plus d’informations sur la conversion des paramètres de sortie, veuillez consulter l’article suivant Paramètres de sortie.

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;
Copy
Exécution de scripts 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;
$$;
Copy

Problèmes connus

1. Several Unsupported Assignment Statements

Actuellement, la transformation des variables de type curseur, collection, enregistrement et définies par l’utilisateur n’est pas prise en charge par Snow Scripting. Par conséquent, les instructions d’affectation utilisant ces variables sont commentées et marquées comme n’étant pas prises en charge. Le remplacement de ces variables par des types de données semi-structurées Snowflake pourrait constituer une solution de contournement dans certains scénarios.

CALL

Description

Il existe deux types d’instructions d’appel dans Oracle :

1-Instruction CALL :

Utilisez l’instruction CALL pour exécuter une routine (une procédure ou une fonction autonome, ou une procédure ou une fonction définie dans un type ou un paquet) à partir de SQL. (Référence linguistique Oracle SQL CALL)

2-Spécification d’appel .

Une spécification d’appel déclare une méthode Java ou un sous-programme en langue C de sorte qu’il puisse être invoqué à partir de PL/SQL. (Référence linguistique Oracle SQL Spécification d’appel)

La spécification CALL n’est pas prise en charge par le Snowflake Scripting car elle fait partie des bibliothèques de développement pour C et JAVA, et n’est pas une instruction SQL. Cette instruction n’est donc pas transformée.

Problèmes connus

Aucun problème n’a été constaté.

EWIs connexes

Pas d’EWIs connexes.

CASE

Description

L’instruction CASE choisit une séquence de conditions et exécute l’instruction correspondante. Pour plus d’informations sur Oracle CASE, cliquez ici.

Note

Certaines parties du code de sortie sont omises pour des raisons de clarté.

Cas simple

 [ <<label>> ] CASE case_operand
  WHEN boolean_expression THEN statement ;
  [ WHEN boolean_expression THEN statement ; ]...
  [ ELSE statement [ statement ]... ;
END CASE [ label ] ;
Copy
 CASE ( <expression_to_match> )
    WHEN <expression> THEN
        <statement>;
        [ <statement>; ... ]
    [ WHEN ... ]
    [ ELSE
        <statement>;
        [ <statement>; ... ]
    ]
END [ CASE ] ;
Copy

Cas recherché

 [ <<label>> ] CASE
  WHEN boolean_expression THEN statement ;
  [ WHEN boolean_expression THEN statement ; ]...
  [ ELSE statement [ statement ]... ;
END CASE [ label ];
Copy
 CASE
    WHEN <boolean_expression> THEN
        <statement>;
        [ <statement>; ... ]
    [ WHEN ... ]
    [ ELSE
        <statement>;
        [ <statement>; ... ]
    ]
END [ CASE ] ;
Copy

Modèles d’échantillons de sources

Échantillon de table auxiliaire

 CREATE TABLE case_table(col varchar(30));
Copy
 CREATE OR REPLACE TABLE case_table (col varchar(30))
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"oracle"}}'
;
Copy

Cas simple

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;
Copy
|COL          |
|-------------|
|Poor         |
|No such grade|
|Excellent    |


Copy
Exécution de scripts 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;
Copy
|COL          |
|-------------|
|Poor         |
|No such grade|
|Excellent    |


Copy

Cas recherché

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;
Copy
|COL          |
|-------------|
|Poor         |
|No such grade|
|Excellent    |


Copy
Exécution de scripts 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;
Copy
|COL          |
|-------------|
|Poor         |
|No such grade|
|Excellent    |


Copy

Problèmes connus

1. Labels are not supported in Snowflake Scripting CASE syntax

Les étiquettes sont commentées ou supprimées en fonction de leur position.

connexesEWIS

  1. SSC-EWI-0094 : Déclaration d’étiquette non prise en charge.

  2. SSC-FDM-0007 : Élément avec des dépendances manquantes.

COMPOUND STATEMENTS

Avertissement

Les informations de cette section, en cours de modification, sont sujettes à modification.

Note

Certaines parties du code de sortie sont omises pour des raisons de clarté.

Description générale

L’unité de base d’un programme source PL/SQL est le bloc, qui regroupe les déclarations et instructions connexes.

Un bloc PL/SQL est défini par les mots-clés DECLARE, BEGIN, EXCEPTION et END. Ces mots-clés divisent le bloc en une partie déclarative, une partie exécutable et une partie de traitement des exceptions. Seule la partie exécutable est exigée. (Blocs anonymes PL/SQL)

Le bloc BEGIN...END dans Oracle peut présenter les caractéristiques suivantes :

  1. Être imbriqué.

  2. Contenir l’instruction DECLARE pour les variables.

  3. Grouper plusieurs instructions SQL ou PL/SQL.

Syntaxe Oracle

 [DECLARE <Variable declaration>]
BEGIN
  <Executable statements>
[EXCEPTION <Exception handler>]
END
Copy

Syntaxe Snowflake

 BEGIN
    <statement>;
    [ <statement>; ... ]
[ EXCEPTION <exception_handler> ]
END;
Copy

Note

Dans Snowflake, un bloc BEGIN/END peut être la construction de premier niveau à l’intérieur d’un bloc anonyme (documentation de Snowflake).

Modèles d’échantillons de sources

1. IF-ELSE block

Consultez la documentation suivante sur les instructions IF pour en savoir plus : Traduction des instructions SnowConvert IF et documentation sur l’instruction IF de Snowflake

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;
Copy
Statement processed.
You are an adult.

Copy
Snowflake

Avertissement

Lors de l’appel d’une procédure ou d’une fonction définie par l’utilisateur (UDF), il est nécessaire de générer du code pour prendre en charge l’équivalence avec la variable call_results. Dans ce cas, sert à imprimer l’information.

Consultez la fonction définie par l’utilisateur (UDF) utilisée ici.

 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;
Copy
 anonymous block
You are an adult.
Copy

2. CASE statement

Pour plus d’informations, consultez la documentation suivante : Documentation de l’instruction SnowConvert CASE et Documentation 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;
Copy
Statement processed.
Tuesday

Copy
Snowflake

Avertissement

Lors de l’appel d’une procédure ou d’une fonction définie par l’utilisateur (UDF), il est nécessaire de générer du code pour prendre en charge l’équivalence avec la variable call_results. Dans ce cas, sert à imprimer l’information.

Consultez la fonction définie par l’utilisateur (UDF) utilisée ici.

 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;
Copy
 anonymous block
Tuesday
Copy

3. LOOP statements

Pour plus d’informations, consultez la documentation suivante : SnowConvert FOR LOOP et la documentation Snowflake LOOP et documentation FOR.

Oracle
 BEGIN
    FOR i IN 1..10 LOOP
        NULL;
    END LOOP;
END;
Copy
Statement processed.

Copy
Snowflake
 BEGIN
    FOR i IN 1 TO 10 LOOP
        NULL;
    END LOOP;
END;
Copy
anonymous block

Copy

4. Procedure call and OUTPUT parameters

Les blocs anonymes dans Oracle peuvent contenir des appels de procédure. En outre, la documentation suivante peut s’avérer utile : Documentation sur les procédures SnowConvert.

L’exemple suivant utilise les paramètres OUT, les informations sur la transformation en cours peuvent être trouvées ici : Paramètres 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;
/
Copy
Statement processed.
The sum of 10 and 20 is 30

Copy
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;
Copy
anonymous block
The sum of 10 and 20 is 30

Copy

5. Alter session

Pour plus d’informations, consultez la documentation suivante : Documentation Alter session.

Remarquez que dans Oracle, le bloc BEGIN...END doit utiliser l’instruction EXECUTE IMMEDIATE pour exécuter les instructions 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;
Copy
Statement processed.
Done

Copy
Snowflake

Avertissement

L’avertissement suivant pourrait être ajouté à l’avenir :\ /***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;
Copy
anonymous block
Done

Copy

6. Cursors

L’exemple suivant montre l’utilisation d’un curseur à l’intérieur d’un bloc BEGIN...END. Consultez la documentation suivante pour en savoir plus : Documentation sur le curseur.

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;
Copy
Statement processed.
NameA NameZ

Copy
Snowflake

Avertissement

Lors de l’appel d’une procédure ou d’une fonction définie par l’utilisateur (UDF), il est nécessaire de générer du code pour prendre en charge l’équivalence avec la variable call_results. Dans ce cas, sert à imprimer l’information.

Consultez la fonction définie par l’utilisateur (UDF) utilisée ici.

 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;
Copy
anonymous block
NameA NameZ

Copy

7. Select statements

Pour plus d’informations, consultez la documentation suivante : Documentation sur les sélections.

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;
Copy
Statement processed.
2

Copy
Snowflake

Avertissement

Lors de l’appel d’une procédure ou d’une fonction définie par l’utilisateur (UDF), il est nécessaire de générer du code pour prendre en charge l’équivalence avec la variable call_results. Dans ce cas, sert à imprimer l’information.

Consultez la fonction définie par l’utilisateur (UDF) utilisée ici.

 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;
Copy
anonymous block
2

Copy

8. Join Statements

Pour plus d’informations, consultez la documentation suivante : Documentation sur les jointures.

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;
Copy
Statement processed.
7

Copy
Snowflake

Avertissement

Lors de l’appel d’une procédure ou d’une fonction définie par l’utilisateur (UDF), il est nécessaire de générer du code pour prendre en charge l’équivalence avec la variable call_results. Dans ce cas, sert à imprimer l’information.

Consultez la fonction définie par l’utilisateur (UDF) utilisée ici.

 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;
Copy

9. Exception handling

Oracle
 DECLARE
      v_result NUMBER;
BEGIN
   v_result := 1 / 0;
   EXCEPTION
      WHEN ZERO_DIVIDE THEN
         DBMS_OUTPUT.PUT_LINE( SQLERRM );
END;
Copy
Statement processed.
ORA-01476: divisor is equal to zero

Copy
Snowflake

Avertissement

L’exception ZERO_DIVIDE dans Snowflake n’est pas prise en charge.

 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;
Copy
anonymous block
Division by zero

Copy

Problèmes connus

  1. Instructions GOTO non prises en charge dans Oracle.

  2. Les exceptions qui utilisent les instructions GOTO peuvent également être affectées.

  3. La fonctionnalité du curseur peut être adaptée dans le cadre des restrictions actuelles sur les traductions.

EWIs connexes

  1. SSC-EWI-0027 : L’instruction suivante utilise une variable/littéral avec une requête invalide et elle ne sera pas exécutée.

  2. SSC-EWI-OR0036 : Problèmes de résolution de types, l’opération arithmétique peut ne pas se comporter correctement entre une chaîne et une date.

  3. SSC-FDM-OR0035 : DBMS_OUTPUT.PUTLINE vérifie la mise en œuvre de l’UDF.

  4. SSC-FDM-0006 : La colonne de type nombre peut ne pas se comporter de la même manière dans Snowflake.

  5. SSC-PRF-0004 : Cette instruction utilise le curseur for loop.

  6. SSC-EWI-0030 : L’instruction ci-dessous a des utilisations de SQL dynamique

CONTINUE

Description

L’instruction CONTINUE quitte l’itération courante d’une boucle, de manière conditionnelle ou inconditionnelle, et transfère le contrôle à l’itération suivante de la boucle courante ou d’une boucle étiquetée qui l’entoure. (Référence linguistique Oracle PL/SQL Instruction CONTINUE)

Note

Certaines parties du code de sortie sont omises pour des raisons de clarté.

 CONTINUE [ label ] [ WHEN boolean_expression ] ;
Copy
 { CONTINUE | ITERATE } [ <label> ] ;
Copy

Modèles d’échantillons de sources

1. Simple Continue

Le code ignore l’instruction INSERT en utilisant CONTINUE.

Ce cas est équivalent sur le plan fonctionnel.

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;
Copy
ITERATOR|
--------+

Copy
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;
Copy
ITERATOR|
--------+

Copy

2. Continue with condition

Le code ignore l’insertion des nombres pairs en utilisant CONTINUE.

Note

Ce cas n’est pas équivalent sur le plan fonctionnel, mais vous pouvez transformer la condition en une instruction 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;
Copy
ITERATOR|
--------+
1       |
3       |
5       |
7       |
9       |
11      |
13      |
15      |
17      |
19      |
21      |

Copy
Exécution de scripts 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;
Copy
ITERATOR|
--------+
1       |
3       |
5       |
7       |
9       |
11      |
13      |
15      |
17      |
19      |
21      |

Copy

3. Continue with label and condition

Le code ignore la ligne 19 et la boucle intérieure n’est exécutée qu’une seule fois parce que CONTINUE passe toujours à la boucle extérieure à l’aide de l’étiquette.

Ce cas est équivalent sur le plan fonctionnel à l’application du même processus que l’échantillon précédent.

Note

Notez que les étiquettes seront commentées.

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;
Copy
ITERATOR|
--------+
I1      |
K1      |
K2      |
K3      |
K4      |
K5      |
I2      |
I3      |
I4      |
I5      |
I6      |
I7      |
I8      |
I9      |
I10     |
I11     |

Copy
Exécution de scripts 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;
Copy
ITERATOR|
--------+
I1      |
K1      |
K2      |
K3      |
K4      |
K5      |
I2      |
I3      |
I4      |
I5      |
I6      |
I7      |
I8      |
I9      |
I10     |
I11     |

Copy

Problèmes connus

Aucun problème n’a été constaté.

EWIs connexes

  1. SSC-EWI-0094 : Déclaration d’étiquette non prise en charge.

CREATE PROCEDURE

Description

Note

Certaines parties du code de sortie sont omises pour des raisons de clarté.

Une procédure est un groupe d’instructions PL/SQL que vous pouvez appeler par leur nom. Une spécification d’appel (parfois appelée call spec) déclare une méthode Java ou une routine en langage de troisième génération (3GL) de manière à ce qu’elle puisse être appelée à partir de SQL et PL/SQL. La spécification d’appel indique à la base de données Oracle quelle méthode Java doit être invoquée lors d’un appel. Il indique également à la base de données les conversions de type à effectuer pour les arguments et la valeur de retour. Référence linguistique Oracle SQL Créer une procédure.

Pour plus d’informations sur Oracle Créer une procédure, cliquez ici.

 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 } } ;
Copy

Pour plus d’informations sur Snowflake Créer une procédure, cliquez ici.

 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>'
Copy

Modèles d’échantillons de sources

1. Basic Procedure

 CREATE OR REPLACE PROCEDURE PROC1
IS
BEGIN
null;
END;
Copy
 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;
$$;
Copy

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;
Copy
 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;
$$;
Copy
Paramètres de sortie

Snowflake n’autorise pas les paramètres de sortie dans les procédures, un moyen de simuler ce comportement pourrait être de déclarer une variable et de renvoyer sa valeur à la fin de la procédure.

Paramètres avec valeurs par défaut

Snowflake ne permet pas de définir des valeurs par défaut pour les paramètres dans les procédures, un moyen de simuler ce comportement pourrait être de déclarer une variable avec la valeur par défaut ou de surcharger la procédure.

3. Procedure with Additional Settings

 CREATE OR REPLACE PROCEDURE proc3
DEFAULT COLLATION USING_NLS_COMP
AUTHID CURRENT_USER
AS
BEGIN
NULL;
END;
Copy
 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;
$$;
Copy

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;
Copy
 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;
$$;
Copy

5. Procedure with empty RETURN statements

Dans les procédures Oracle, vous pouvez avoir des instructions RETURN vides pour terminer l’exécution d’une procédure. Dans Snowflake Scripting, les procédures peuvent comporter des instructions RETURN, mais elles doivent avoir une valeur. Par défaut, toutes les instructions RETURN vides sont converties avec une valeur NULL.

 -- Procedure with empty return
CREATE OR REPLACE PROCEDURE MY_PROC
IS
BEGIN
   NULL;
   RETURN;
END;
Copy
 -- 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;
$$;
Copy
Instructions RETURN dans les procédures avec des paramètres de sortie

Dans les procédures avec des paramètres de sortie, au lieu d’une valeur NULL, une valeur OBJECT_CONSTRUCT sera utilisée dans les instructions RETURN vides pour simuler les paramètres de sortie dans 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;
Copy
 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;
$$;
Copy

6. Procedure with DEFAULT parameters

Les paramètres DEFAULT permettent d’initialiser les paramètres nommés avec des valeurs par défaut si aucune valeur n’est transmise.

 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;
Copy
 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;
Copy

Problèmes connus

1. Unsupported OUT parameters

Les procédures Snowflake n’ont pas d’option native pour les paramètres de sortie.

2. Unsupported Oracle additional settings

Les paramètres et clauses Oracle suivants ne sont pas pris en charge par les procédures Snowflake :

  • sharing_clause

  • default_collation_option

  • invoker_rights_clause

  • accessible_by_clause

  • java_declaration

  • c_declaration

connexesEWIS

  1. SSC-EWI-0058 : La fonctionnalité n’est pas actuellement prise en charge par Snowflake Scripting

  2. SSC-EWI-OR0097 : Les propriétés des procédures ne sont pas prises en charge dans les procédures Snowflake.

  3. SSC-FDM-OR0012: Les instructions COMMIT et ROLLBACK exigent une configuration adéquate pour fonctionner comme prévu.

  4. SSC-PRF-0003 : Fetch à l’intérieur d’une boucle est considéré comme un modèle complexe, ce qui pourrait dégrader les performances de Snowflake.

  5. SSC-PRF-0004 : Cette instruction utilise le curseur for loop.

  6. SSC-EWI-0030 : L’instruction ci-dessous a des utilisations de SQL dynamique

DECLARE

Note

Certaines parties du code de sortie sont omises pour des raisons de clarté.

Description

L’instruction Oracle DECLARE est une partie facultative de l’instruction de bloc PL/SQL. Elle permet la création de variables, de constantes, de déclarations et de définitions de procédures, de déclarations et de définitions de fonctions, d’exceptions, de curseurs, de types et de bien d’autres instructions. Pour plus d’informations sur Oracle DECLARE, cliquez ici.

 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 ] ;
Copy
 [ 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> ] ;
Copy

Modèles d’échantillons de sources

Déclaration de variables

 variable_declaration::= 
variable datatype [ [ NOT NULL] {:= | DEFAULT} expression ] ;
Copy
 <variable_name> <type>;

<variable_name> DEFAULT <expression> ;

<variable_name> <type> DEFAULT <expression> ;
Copy
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;
Copy
Exécution de scripts 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;
$$;
Copy

Déclaration de constantes

Avertissement

Les constantes ne sont pas prises en charge dans Snowflake Scripting, mais elles sont transformées en variables pour simuler le comportement.

 constant_declaration::=
constant CONSTANT datatype [NOT NULL] { := | DEFAULT } expression ;
Copy
 <variable_name> <type>;

<variable_name> DEFAULT <expression> ;

<variable_name> <type> DEFAULT <expression> ; 
Copy
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;
Copy
Exécution de scripts 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;
$$;
Copy

Déclaration de curseurs

 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
  }
Copy
 <cursor_name> CURSOR [ ( <argument> [, <argument> ... ] ) ]
        FOR <query> ;
Copy

La _ déclaration de curseur _ Oracle n’est pas une exigence et peut donc être commentée dans le code de sortie. La _ définition de curseur _ sera utilisée à la place de et elle sera convertie en _ déclaration de curseur _ de Snowflake Scripting. Veuillez consulter la section CURSOR pour obtenir plus d’informations sur la définition du curseur.

Déclaration d’exceptions

La déclaration d’exceptions peut parfois être suivie de l’initialisation de l’exception, la transformation actuelle prend les deux et les fusionne dans la déclaration d’exception de Snowflake Scripting. Le PRAGMA EXCEPTION_INIT d’origine sera commenté.

 exception_declaration::= exception EXCEPTION;

PRAGMA EXCEPTION_INIT ( exception, error_code ) ;
Copy
 <exception_name> EXCEPTION [ ( <exception_number> , '<exception_message>' ) ] ;
Copy
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;
Copy
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;
$$;
Copy

Cas non pris en charge

Les instructions de déclaration Oracle suivantes ne sont pas prises en charge par le bloc de déclaration Snowflake Scripting :

  1. Déclaration des variables de curseur.

  2. Déclaration des variables de collection.

  3. Enregistrement de la déclaration des variables.

  4. Définition du type (toutes ses variantes).

  5. Déclaration et définition des fonctions.

  6. Déclaration et définition des procédures.

Known issues

1. The variable declarations with NOT NULL constraints are not supported by Snow Scripting.

La création de variables avec la contrainte NOT NULL provoque une erreur dans Snow Scripting.

2. The cursor declaration has no equivalent to Snowflake Scripting.

La déclaration de curseur Oracle est inutile et peut donc être commentée dans le code de sortie. La définition de curseur sera utilisée à la place et sera convertie en déclaration de curseur Snowflake Scripting.

3. The exception code exceeds Snowflake Scripting limits.

Le code d’exception Oracle est supprimé lorsqu’il dépasse les limites du code Snowflake Scripting. Le code d’exception doit être un entier compris entre -20000 et -20999.

3. The not supported cases.

Certaines instructions de déclaration Oracle ne sont pas prises en charge par le bloc de déclaration de Snowflake Scripting. Elles peuvent donc faire l’objet d’un commentaire et d’un avertissement.

Related EWIS

  1. SSC-EWI-OR0051 : PRAGMA EXCEPTION_INIT n’est pas pris en charge.

  2. SSC-EWI-OR0099 : Le code d’exception dépasse la limite de Snowflake Scripting.

  3. SSC-FDM-0016 : Les constantes ne sont pas prises en charge par Snowflake Scripting. Il a été transformé en variable.

  4. SSC-FDM-OR0025 : La contrainte Not Null n’est pas prise en charge dans les procédures Snowflake.

DEFAULT PARAMETERS

Note

Certaines parties du code de sortie sont omises pour des raisons de clarté.

Description

Un paramètre par défaut est un paramètre qui a une valeur au cas où un argument n’est pas transmis dans l’appel de la procédure ou de la fonction. Comme Snowflake ne prend pas en charge les paramètres par défaut, SnowConvert insère la valeur par défaut dans l’appel de la procédure ou de la fonction.

Dans la déclaration, la clause DEFAULT VALUE du paramètre est supprimée. Les deux syntaxes, le symbole := et la clause DEFAULT, sont prises en charge.

Modèles d’échantillons de sources

Échantillon de code auxiliaire

 CREATE TABLE TABLE1(COL1 NUMBER, COL2 NUMBER);
CREATE TABLE TABLE2(COL1 NUMBER, COL2 NUMBER, COL2 NUMBER);0016
Copy
 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"}}'
;
Copy

Déclaration des paramètres par défaut

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;
Copy
Exécution de scripts 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;
$$;
Copy

Appel de procédures avec des paramètres par défaut

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;
Copy
Exécution de scripts 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;
$$;
Copy

Afin de vérifier que la fonctionnalité est correctement émulée, la requête suivante va exécuter la procédure et un SELECT à partir de la table mentionnée précédemment.

Oracle
 CALL PROC_WITH_DEFAULT_CALLS();

SELECT * FROM TABLE1;
Copy
|COL1|COL2|
|----|----|
|10  |15  |
|10  |1   |
|10  |15  |
|10  |2   |
|1   |2   |


Copy
Exécution de scripts Snowflake
 CALL PROC_WITH_DEFAULT_CALLS();

SELECT * FROM TABLE1;
Copy
|COL1|COL2|
|----|----|
|10  |15  |
|10  |1   |
|10  |15  |
|10  |2   |
|1   |2   |


Copy

Appel de procédures avec des arguments nommés et des paramètres par défaut

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;
Copy
Exécution de scripts 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;
$$;
Copy

Afin de vérifier que la fonctionnalité est correctement émulée, la requête suivante va exécuter la procédure et un SELECT à partir de la table mentionnée précédemment.

Oracle
 CALL PROC_WITH_DEFAULT_CALLS2();

SELECT * FROM TABLE2;
Copy
|COL1|COL2|COL3|
|----|----|----|
|10  |20  |30  |
|10  |20  |30  |
|20  |30  |10  |
|100 |30  |10  |
|100 |10  |30  |
|100 |10  |1000|


Copy
Exécution de scripts Snowflake
 CALL PROC_WITH_DEFAULT_CALLS2();

SELECT * FROM TABLE2;
Copy
|COL1|COL2|COL3|
|----|----|----|
|10  |20  |30  |
|10  |20  |30  |
|20  |30  |10  |
|100 |30  |10  |
|100 |10  |30  |
|100 |10  |1000|


Copy

Problèmes connus

1. Aucun problème n’a été trouvé

EWIs connexes

Pas d’EWIs connexes.

EXECUTE IMMEDIATE

Description

L’instruction EXECUTE IMMEDIATE construit et exécute une instruction dynamique SQL en une seule opération.

La version dynamique native de SQL utilise l’instruction EXECUTE IMMEDIATE pour traiter la plupart des instructions dynamiques SQL. (Référence linguistique Oracle PL/SQL Instruction EXECUTE IMMEDIATE)

 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> }
Copy

Snowflake Scripting prend en charge cette instruction, avec toutefois quelques différences fonctionnelles. Pour plus d’informations sur l’homologue de Snowflake, consultez la documentation sur Snowflake EXECUTE IMMEDIATE.

 EXECUTE IMMEDIATE <dynamic statement> ;

dynamic statement::= {'<string literal>' | <variable> | $<session variable>}
Copy

Modèles d’échantillons de sources

Les échantillons suivants créent une table et tentent de la supprimer à l’aide de la fonction Execute Immediate.

Utilisation d’une chaîne codée en dur

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;
Copy
Exécution de scripts 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;
Copy

Stockage de la chaîne dans une variable

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;
Copy
Exécution de scripts 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;
Copy

Concaténation des paramètres dans une instruction dynamique

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;
Copy
Exécution de scripts 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;
Copy

Transformation de clause 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;
Copy
COL1|
----+
   1|

Copy
Exécution de scripts Snowflake

Note

Veuillez noter que les parenthèses sont exigées pour les paramètres de la clause USING dans 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;
Copy
COL1|
----+
   1|

Copy

Problèmes connus

1. Immediate Execution results cannot be stored in variables.

SnowScripting ne prend pas en charge les clauses INTO et BULK COLLECT INTO. Pour cette raison, les résultats devront être transmis par d’autres moyens.

2. Numeric Placeholders

Les noms numériques des espaces réservés ne sont actuellement pas reconnus par SnowConvert, mais une correction est en cours.

3. Argument Expressions are not supported by Snowflake Scripting

Dans Oracle, il est possible d’utiliser des expressions comme arguments pour la clause d’utilisation ; cependant, ce cas n’est pas pris en charge par Snowflake Scripting, et elles sont commentées.

4. Dynamic SQL Execution queries may be marked incorrectly as non-runnable.

Dans certains cas, une instruction d’exécution peut faire l’objet d’un commentaire, que son exécution soit sûre ou non, veuillez en tenir compte :

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;
Copy
Exécution de scripts Snowflake

Note

Veuillez noter que les parenthèses sont exigées pour les paramètres de la clause USING dans 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;
$$;
Copy

EWIs connexes

  1. SSC-EWI-0027 : Variable avec requête invalide.

  2. SSC-EWI-0030 : L’instruction ci-dessous a des utilisations de SQL dynamique.

EXIT

Note

Certaines parties du code de sortie sont omises pour des raisons de clarté.

Description

L’instruction EXIT quitte l’itération courante d’une boucle, de manière conditionnelle ou inconditionnelle, et transfère le contrôle à la fin de la boucle courante ou d’une boucle étiquetée qui l’entoure. (Référence linguistique Oracle PL/SQL Instruction EXIT)

 EXIT [ label ] [ WHEN boolean_expression ] ;
Copy
 { BREAK | EXIT } [ <label> ] ;
Copy

Modèles d’échantillons de sources

Note

Notez que vous pouvez remplacer EXITpar BREAKet que tout fonctionnera de la même manière.

1. Simple Exit

Le code ignore l’instruction INSERT en utilisant EXIT.

Ce cas est équivalent sur le plan fonctionnel.

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;
Copy
ITERATOR|
--------+

Copy
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;
Copy
ITERATOR|
--------+

Copy

2. Exit with condition

Le code quitte la boucle lorsque l’itérateur est supérieur à 5.

Ce cas est fonctionnellement équivalent en transformant la condition en une instruction 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;
Copy
ITERATOR|
--------+
1       |
2       |
3       |
4       |
5       |
6       |

Copy
Exécution de scripts 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;
Copy
ITERATOR|
--------+
1       |
2       |
3       |
4       |
5       |
6       |

Copy

3. Exit with label and condition

Le code casse les deux boucles en utilisant l’instruction EXIT qui pointe vers la boucle extérieure.

Ce cas est équivalent sur le plan fonctionnel à l’application du même processus que l’échantillon précédent.

Note

Notez que les étiquettes seront commentées.

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;
Copy
ITERATOR|
--------+
I1      |
K1      |
K2      |
K3      |
K4      |
K5      |

Copy
Exécution de scripts 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;
Copy
ITERATOR|
--------+
I1      |
K1      |
K2      |
K3      |
K4      |
K5      |

Copy

Problèmes connus

Aucun problème n’a été constaté.

EWIs connexes

  1. SSC-EWI-0094 : Déclaration d’étiquette non prise en charge.

EXPRESSIONS

Note

Certaines parties du code de sortie sont omises pour des raisons de clarté.

Description

La table suivante résume la manière de transformer les différents types d’expression Oracle en Snowflake Scripting.

Syntaxe

Statut de conversion

Remarques

Expressions de caractères

Partiel

Scénarios communs partiellement pris en charge

Expressions numériques

Partiel

Scénarios communs partiellement pris en charge

Expressions de date

Partiel

Scénarios communs partiellement pris en charge

Expressions booléennes

Partiel

Expressions booléennes non prises en charge

Expressions de cas simples

Complet

N/A

Expressions de cas recherchés

Complet

N/A

Constructeur de collection

Non traduit

Snowflake n’a pas d’équivalent natif pour les collections Oracle. Voir Collections et enregistrements.

Expressions qualifiées

Non traduit

Snowflake n’a pas d’équivalent natif pour les types d’enregistrement Oracle. Voir Collections et enregistrements.

Scénarios communs partiellement pris en charge

Constantes Oracle

Pour plus d’informations, consultez la section Déclaration de constantes 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;
Copy
|COL          |
|-------------|
|CONSTANT TEXT|


Copy
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;
Copy
|COL          |
|-------------|
|CONSTANT TEXT|


Copy

Expressions numériques non prises en charge

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;
Copy
|COL|
|---|
|4  |
|104|
|11 |
|3  |

Copy

Expressions booléennes non prises en charge

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;
Copy

EWIs connexes.

  1. SSC-FDM-0016 : Les constantes ne sont pas prises en charge par Snowflake Scripting. Il a été transformé en variable.

FOR LOOP

Description

À chaque itération de l’instruction FOR LOOP, ses instructions sont exécutées, son index est incrémenté ou décrémenté et le contrôle revient au début de la boucle. (Référence linguistique PL/SQL Instructions FOR LOOP)

 FOR
pls_identifier [ MUTABLE | IMMUTABLE ] [ constrained_type ]
[ , iterand_decl ]

IN

[ REVERSE ] iteration_control pred_clause_seq
[, qual_iteration_ctl]...

LOOP
statement... 
END LOOP [ label ] ;
Copy
 FOR <counter_variable> IN [ REVERSE ] <start> TO <end> { DO | LOOP }
    statement;
    [ statement; ... ]
END { FOR | LOOP } [ <label> ] ;
Copy

Snowflake Scripting prend en charge FOR LOOP qui boucle un nombre de fois spécifié. Les limites supérieure et inférieure doivent être INTEGER. Pour plus d’informations, consultez la documentation Snowflake Scripting.

Le comportement d’Oracle FOR LOOP peut également être modifié à l’aide des instructions :

Modèles d’échantillons de sources

1. FOR LOOP

Ce cas est équivalent sur le plan fonctionnel.

 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;
Copy
 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;
$$;
Copy

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;
Copy
 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;
$$;
Copy

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;
Copy
 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;
$$;
Copy

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;
Copy
 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;
$$;
Copy

Avertissement

La transformation des types personnalisés n’est actuellement pas prise en charge par Snowflake Scripting.

Problèmes connus

1. For With Multiple Conditions

Oracle autorise plusieurs conditions sur un même FOR LOOP, mais Snowflake Scripting n’autorise qu’une seule condition par FOR LOOP. Seule la première condition est migrée et les autres sont ignorées lors de la transformation. Voir SSC-FDM-OR0022.

 FOR i IN REVERSE 1..3,
REVERSE i+5..i+7
LOOP
    NULL;
END LOOP;
Copy
 --** 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;
Copy

2. Variable de compteur mutable ou non mutable

Oracle permet de modifier la valeur de la variable FOR LOOP à l’intérieur de la boucle. La documentation actuelle inclut cette fonctionnalité, mais Snowflake recommande de l’éviter. La modification de la valeur de cette variable peut ne pas se dérouler correctement dans Snowflake Scripting.

3. Nombre entier ou nombre flottant pour la limite supérieure ou inférieure

Snowflake Scripting n’autorise qu’un INTEGER ou une expression qui s’évalue à un INTEGER comme limite de la condition FOR LOOP. Les nombres flottants seront arrondis vers le haut ou vers le bas et modifieront la borne d’origine. Voir SSC-EWI-OR0102.

4. Clauses non prises en charge par Oracle

Oracle autorise des clauses supplémentaires à la condition FOR LOOP. Comme la clause BY pour une incrémentation progressive de la condition. Et la clause WHILE et WHEN pour les expressions booléennes. Ces clauses supplémentaires ne sont pas prises en charge par Snowflake Scripting et sont ignorées lors de la transformation. Voir SSC-EWI-OR0101.

 FOR i IN 5..15 BY 5 LOOP
    NULL;
END LOOP;
Copy
 !!!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;
Copy

5. Formats non pris en charge

Oracle autorise différents types de conditions pour un FOR LOOP. Il prend en charge les expressions booléennes, les collections, les enregistrements… Cependant, le Snowflake Scripting ne prend en charge que FOR LOOP avec des entiers définis comme limites. Tous les autres formats sont marqués comme n’étant pas pris en charge et nécessitent un effort manuel supplémentaire pour être transformés. Voir SSC-EWI-OR0103.

EWIs connexes

  1. SSC-EWI-0058 : La fonctionnalité n’est pas prise en charge actuellement par Snowflake Scripting.

  2. SSC-EWI-0062 : L’utilisation du type personnalisé a été modifiée en variante.

  3. SSC-EWI-OR0100 : For Loop avec plusieurs conditions n’est actuellement pas pris en charge par Snowflake Scripting. Seule la première condition est utilisée.

  4. SSC-EWI-OR0101 : La clause spécifique For Loop n’est actuellement pas prise en charge par Snowflake Scripting.

  5. SSC-EWI-OR0103 : Le format For Loop n’est actuellement pas pris en charge par Snowflake Scripting.

FORALL

Description

L’instruction FORALL exécute une instruction DML plusieurs fois, avec des valeurs différentes dans les clauses VALUES et WHERE. (Référence linguistique Oracle PL/SQL Instruction FORALL).

FORALL index IN bounds_clause [ SAVE ] [ EXCEPTIONS ] dml_statement ;
Copy

Avertissement

Snowflake Scripting n’a pas d’équivalence directe avec l’instruction FORALL, mais peut être émulé avec différentes solutions de contournement pour obtenir une équivalence fonctionnelle.

Modèles d’échantillons de sources

Données de configuration

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);
Copy
 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);
Copy
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);
Copy
 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);
Copy

1. FORALL With Collection of Records

Oracle

Les trois cas ci-dessous ont la même transformation en Snowflake Scripting et sont fonctionnellement équivalents.

 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;
Copy
 COLUMN1| COLUMN2|
--------+--------+
       1|	2|
       1|       2|
       2|       3|
       3|       4|
       4|       5|
       5|       6|

Copy
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;
$$;
Copy
             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|

Copy

Note

Les EWIs SSC-PRF-0001 et SSC-PRF-0003 sont ajoutées à chaque occurrence de FETCH BULK COLLECT dans l’instruction 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;
Copy
 COLUMN1| COLUMN2|
--------+--------+
       1|	2|
       1|       2|
       2|       3|
       3|       4|
       4|       5|
       5|       6|

Copy
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;
$$;
Copy
             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|

Copy

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;
Copy
 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;
Copy
 COLUMN1| COLUMN2|
--------+--------+
       1|	2|
       2|       3|
       3|       4|
       4|       5|
       5|       6|
       1|       2|

Copy
 COLUMN1| COLUMN2|
--------+--------+
       1|	2|

Copy
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;
$$;
Copy
 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;
$$;
Copy
             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|

Copy
             COLUMN1|	             COLUMN2|
--------------------+-----------------------+
1.000000000000000000|	2.000000000000000000|

Copy

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;
Copy
 COLUMN1| COLUMN2|
--------+--------+
       1|	2|
       1|       2|
       2|       3|
       3|       4|
       4|       5|
       5|       6|

Copy
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;
$$;
Copy
             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|

Copy

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;
Copy
 COLUMN1| COLUMN2|
--------+--------+
       1|	2|
       1|       2|
       2|       3|
       3|       4|
       4|       5|
       5|       6|

Copy
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;
$$;
Copy
             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|

Copy

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;
Copy
 COLUMN1| COLUMN2|
--------+--------+
       1|	2|
       1|       2|
       2|       3|
       3|       4|
       4|       5|
       5|       6|

Copy
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;
$$;
Copy
 COLUMN1| COLUMN2|
--------+--------+
       1|	2|
       1|       2|
       2|       3|
       3|       4|
       4|       5|
       5|       6|

Copy

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;
Copy
 COLUMN1| COLUMN2|
--------+--------+
       1|	2|
       1|       2|
       2|       3|
       3|       4|
       4|       5|
       5|       6|

Copy
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;
$$;
Copy
 COLUMN1| COLUMN2|
--------+--------+
       1|	2|
       1|       2|
       2|       3|
       3|       4|
       4|       5|
       5|       6|

Copy

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;
Copy
 COLUMN1| COLUMN2|
--------+--------+
       1|	2|
       1|       2|
       2|       3|
       3|       4|
       4|       5|
       5|       6|

Copy
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;
$$;
Copy
             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|

Copy

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;
Copy
 COLUMN1| COLUMN2|
--------+--------+
   54321|	2|

Copy
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;
$$;
Copy
 COLUMN1| COLUMN2|
--------+--------+
   54321|	2|

Copy

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;
Copy
no data found

Copy
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;
$$;
Copy
Query produced no results

Copy

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;
Copy
 COLUMN1| COLUMN2|
--------+--------+
       1|	2|
      10|      10|       

Copy
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;
Copy
              COLUMN1|	              COLUMN2|
---------------------+-----------------------+
 1.000000000000000000|	 2.000000000000000000| 
10.000000000000000000|	10.000000000000000000|

Copy

Avertissement

La transformation ci-dessus ne fonctionne que si la variable définie dans le paquet est un enregistrement de collections.

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;
Copy
 COLUMN1| COLUMN2|
--------+--------+
       1|	4|
       2|       3|
       3|       4|
       4|       5|
       5|       6|

Copy
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;
$$;
Copy
             COLUMN1|	             COLUMN2|
--------------------+-----------------------+
2.000000000000000000|	3.000000000000000000|
3.000000000000000000|	4.000000000000000000|
4.000000000000000000|	5.000000000000000000|
5.000000000000000000|	6.000000000000000000|
1.000000000000000000|	4.000000000000000000|

Copy

Avertissement

La transformation ci-dessus ne fonctionne que si l’instruction SELECT à l’intérieur de MERGE sélectionne la table DUAL.

13. Default FORALL transformation

Note

Vous pourriez également être intéressé par Assitants des curseurs en masse.

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;
Copy
 COLUMN1| COLUMN2|
--------+--------+
       1|	2|
       1|       2|
       2|       3|
       3|       4|
       4|       5|
       5|       6|

Copy
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;
$$;
Copy
             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|

Copy

Note

Cette transformation n’est effectuée que lorsqu’aucune des transformations mentionnées précédemment ne peut être réalisée.

14. Multiple FORALL inside a LOOP clause

Note

Ce modèle s’applique lorsqu’il y a plus d’un FORALL dans la même procédure et qu’il répond à la structure suivante.

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;
Copy
 COLUMN1| COLUMN2|
--------+--------+
   54321|	2|
   54321|       2|
   54321|       3|
   54321|       4|
   54321|       5|
   54321|       6|

Copy
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;
$$;
Copy
 COLUMN1| COLUMN2|
--------+--------+
   54321|	2|
   54321|       2|
   54321|       3|
   54321|       4|
   54321|       5|
   54321|       6|

Copy

15. Multiple FORALL inside different LOOP clauses

Note

Ce modèle s’applique lorsqu’il y a plus d’un FORALL dans la même procédure et qu’il répond à la structure suivante.

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;
Copy
 COLUMN1| COLUMN2|
--------+--------+
   54321|	2|
   54321|       2|
   54321|       3|
   54321|       4|
   54321|       5|
   54321|       6|

Copy
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;
$$;
Copy
 COLUMN1| COLUMN2|
--------+--------+
   54321|	2|
   54321|       2|
   54321|       3|
   54321|       4|
   54321|       5|
   54321|       6|

Copy

16. FORALL with MERGE INTO with LOG ERRORS

Avertissement

Ce modèle n’est pas encore mis en œuvre

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;
Copy
   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 |


Copy
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;
Copy
                                                                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|


Copy

17. FORALL with INSERT with LOG ERRORS

Avertissement

Ce modèle n’est pas encore mis en œuvre

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;
Copy
   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 |


Copy
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;
Copy
                                                                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|


Copy

Problèmes connus

Aucun problème n’a été constaté.

EWIs connexes

  1. SSC-EWI-0030 : L’instruction ci-dessous a des utilisations de SQL dynamique.

  2. SSC-EWI-0036 : Type de données converti en un autre type de données.

  3. SSC-EWI-0056 : Type de création non pris en charge.

  4. SSC-EWI-0058 : La fonctionnalité n’est pas prise en charge actuellement par Snowflake Scripting.

  5. SSC-EWI-0062 : L’utilisation du type personnalisé a été modifiée en variante.

  6. SSC-EWI-OR0049 : Les constantes de paquet dans les paquets avec état ne sont pas encore prises en charge.

  7. SSC-FDM-0006 : La colonne de type nombre peut ne pas se comporter de la même manière dans Snowflake.

  8. SSC-FDM-0015: Le type personnalisé référencé dans la requête n’a pas été trouvé.

  9. SSC-PRF-0001 : Cette instruction a des utilisations d’opérations de curseur fetch bulk.

  10. SSC-PRF-0003 : Fetch à l’intérieur d’une boucle est considéré comme un modèle complexe, ce qui pourrait dégrader les performances de Snowflake.

IF

Description

L’instruction IF permet d’exécuter ou d’ignorer une séquence d’une ou plusieurs instructions, en fonction de la valeur d’une expression BOOLEAN. Pour plus d’informations sur Oracle IF, cliquez ici.

 IF boolean_expression THEN 
    statement 
    [ statement ]...
[ 
ELSIF boolean_expression THEN 
    statement 
    [ statement ]... ]...
   [ 
ELSE 
statement [ statement ]... ] END IF ;
Copy
 IF ( <condition> ) THEN
    <statement>;
    [ <statement>; ... ]
[
ELSEIF ( <condition> ) THEN
    <statement>;
    [ <statement>; ... ]
]
[
ELSE
    <statement>;
    [ <statement>; ... ]
]
END IF;
Copy

Modèles d’échantillons de sources

Échantillon de table auxiliaire

 CREATE TABLE if_table(col1 varchar(30));
Copy
 CREATE OR REPLACE TABLE PUBLIC.if_table (col1 varchar(30));
Copy

Variantes possibles 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;
Copy
 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;
Copy
 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;
Copy
 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;
Copy
|COL1|
|----|
|one |


Copy
|COL1             |
|-----------------|
|Unexpected input.|


Copy
|COL1 |
|-----|
|three|


Copy
|COL1             |
|-----------------|
|Unexpected input.|


Copy
Exécution de scripts 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;
Copy
 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;
Copy
 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;
Copy
 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;
Copy
|COL1|
|----|
|one |


Copy
|COL1             |
|-----------------|
|Unexpected input.|


Copy
|COL1 |
|-----|
|three|


Copy
|COL1             |
|-----------------|
|Unexpected input.|


Copy

Problèmes connus

Aucun problème n’a été constaté.

connexesEWIS

Pas d’EWIs connexes.

IS EMPTY

Avertissement

Les informations de cette section, en cours de modification, sont sujettes à modification.

Description

Utilisez les conditions IS [[NOT] EMPTY pour vérifier si une table imbriquée spécifiée est vide, que des éléments de la collection soient ou non NULL. (Documentation.)

Syntaxe Oracle

 nested_table IS [ NOT ] EMPTY
Copy

Modèles d’échantillons de sources

Oracle

L’exemple suivant illustre l’utilisation de l’instruction IS EMPTY. L’instruction est appliquée à une table imbriquée dont le type de définition est UDT. La sortie indique le nom des employés qui n’ont pas de numéro de téléphone.

 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;
Copy

EMP_NAME

Jane Smith

Snowflake

La requête Snowflake présentée ci-dessous est l’équivalence de la fonctionnalité de l’instruction IS EMPTY. En particulier, l’instruction IS EMPTY fait la différence entre un objet NULL et un objet EMPTY.

Remarquez que les types définis par l’utilisateur sont transformés en VARIANT. Le type VARIANT dans Snowflake permet de stocker des objets et des tableaux. Comme une table imbriquée est une séquence d’informations, le type ARRAY est le type le plus approprié pour les redéfinir et vérifier si l’objet ARRAY est vide.

La solution équivalente ARRAY_SIZE permet également de demander la nullité de la table imbriquée (transformée en VARIANT). En d’autres termes, le type VARIANT peut également stocker des NULLs et des ARRAYs vides.

 !!!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;
Copy

EMP_NAME

Jane Smith

Autres combinaisons possibles

DescriptionOracleSnowflake
Ask for a IS NOT EMPTY
(...)
WHERE phone_numbers_col IS NOT EMPTY;
```
(...)
WHERE ARRAY_SIZE(phone_numbers_col) != 0;
```
Ask for NULL instead of EMPTY
(...)
WHERE phone_numbers_col IS NULL;
```
(...)
WHERE ARRAY_SIZE(phone_numbers_col) IS NULL;
```

Problèmes connus

1. User-defined types are being transformed into Variant.

Les types définis par l’utilisateur ne sont pas pris en charge et sont donc transformés en types de variantes, ce qui peut nécessiter un effort manuel pour garantir certaines fonctions.

Consultez la page suivante pour plus d’informations :

create-type-statement

2. Nested tables are not supported.

Les tables imbriquées ne sont pas prises en charge actuellement. La meilleure approche sur la base de cette équivalence consiste à traiter les tables imbriquées comme des variantes, mais à déclarer des tableaux contenant des données JSON et à exécuter la fonction PARSE_JSON Snowflake pour remplir les informations imbriquées.

Consultez les pages suivantes pour plus d’informations :

nested-table-array-type-definition.md

nested-table-type-definition.md

3. Insert statements are not supported for User-defined types.

Les types définis par l’utilisateur n’étant pas pris en charge, les instructions d’insertion dans ces types ne sont pas prises en charge. Dans les tables imbriquées, l’instruction INSERT INTO ... VALUES doit être remplacée par INSERT INTO...SELECT, car la fonction ARRAY_CONSTRUCT est censée être utilisée dans ce modèle.

Consultez la page suivante pour plus d’informations :

object-type-definition.md

4. Logic should be adapted to ARRAY types.

Comme les tables imbriquées doivent être transformées de manière équivalente à VARIANT et se comporter comme ARRAYs,, la fonctionnalité et la logique de mise en œuvre des procédures et d’interaction avec les données doivent être adaptées.

Examinez les exemples suivants :

4.1 Équivalence des procédures
 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;
Copy
 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;
$$;
Copy

PROC1

IS EMPTY

4.2 Instructions de sélection

Les sorties peuvent différer d’une table à l’autre sur les ARRAYs.

Oracle
 SELECT
    t.*
FROM
    employee e,
    table(e.phone_numbers_col) t
WHERE
    emp_id = 1;
Copy

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;
Copy

PHONE_NUMBERS_COL

[ 1234567890 ]

EWIs connexes

  1. SSC-EWI-0056 : Type de création non pris en charge.

  2. SSC-EWI-0062 : L’utilisation du type personnalisé a été modifiée en variante.

  3. SSC-EWI-0073 : En attente de l’examen de l’équivalence fonctionnelle.

  4. SSC-EWI-OR0035 : La fonction de table n’est pas prise en charge lorsqu’elle est utilisée comme une collection d’expressions.

  5. SSC-FDM-0006 : La colonne de type nombre peut ne pas se comporter de la même manière dans Snowflake.

  6. SSC-FDM-0015: Le type personnalisé référencé dans la requête n’a pas été trouvé.

  7. SSC-FDM-OR0035 : DBMS_OUTPUT.PUTLINE vérifie la mise en œuvre de l’UDF.

LOCK TABLE

Note

Instruction non pertinente.

Avertissement

Remarquez que cette instruction est retirée de la migration parce qu’il s’agit d’une syntaxe non pertinente. Cela signifie qu’elle n’est pas exigée dans Snowflake.

Description

Dans Oracle, l’instruction LOCK TABLE permet d’acquérir explicitement un verrou de table partagé ou exclusif sur la table spécifiée. Le verrou de table dure jusqu’à la fin de la transaction en cours. Pour plus d’informations, cliquez ici.

Syntaxe

 LOCK TABLE tableName IN { SHARE | EXCLUSIVE } MODE
Copy

Modèles d’échantillons de sources

Table verrouillée

Notez que dans cet exemple, l’instruction LOCK TABLE a été supprimée. En effet, Snowflake gère le verrouillage d’une manière différente, par le biais de transactions.

 LOCK TABLE table1 IN EXCLUSIVE MODE;
Copy
 [Empty output]
Copy

LOG ERROR

Note

Certaines parties du code de sortie sont omises pour des raisons de clarté.

Description

L’instruction FORALL exécute une instruction DML plusieurs fois, avec des valeurs différentes dans les clauses VALUES et WHERE. (Référence linguistique Oracle PL/SQL Instruction FORALL).

FORALL index IN bounds_clause [ SAVE ] [ EXCEPTIONS ] dml_statement ;
Copy

Avertissement

Snowflake Scripting n’a pas d’équivalence directe avec l’instruction FORALL, mais peut être émulé avec différentes solutions de contournement pour obtenir une équivalence fonctionnelle.

Modèles d’échantillons de sources

Données de configuration

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);
Copy
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);
Copy

1. MERGE INTO Inside a FORALL

Oracle

Les trois cas ci-dessous ont la même transformation en Snowflake Scripting et sont fonctionnellement équivalents.

 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;
Copy
   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 |


Copy
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;
Copy
             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|

Copy

Note

Les EWIs MSCCP0005 et SSC-PRF-0003 sont ajoutés à chaque occurrence de FETCH BULK COLLECT dans l’instruction 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;
Copy
 COLUMN1| COLUMN2|
--------+--------+
       1|	2|
       1|       2|
       2|       3|
       3|       4|
       4|       5|
       5|       6|

Copy
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;
$$;
Copy
             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|

Copy

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;
Copy
 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;
Copy
 COLUMN1| COLUMN2|
--------+--------+
       1|	2|
       2|       3|
       3|       4|
       4|       5|
       5|       6|
       1|       2|

Copy
 COLUMN1| COLUMN2|
--------+--------+
       1|	2|

Copy
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;
$$;
Copy
 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;
$$;
Copy
             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|

Copy
             COLUMN1|	             COLUMN2|
--------------------+-----------------------+
1.000000000000000000|	2.000000000000000000|

Copy

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;
Copy
 COLUMN1| COLUMN2|
--------+--------+
       1|	2|
       1|       2|
       2|       3|
       3|       4|
       4|       5|
       5|       6|

Copy
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;
$$;
Copy
             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|

Copy

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;
Copy
 COLUMN1| COLUMN2|
--------+--------+
       1|	2|
       1|       2|
       2|       3|
       3|       4|
       4|       5|
       5|       6|

Copy
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;
$$;
Copy
             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

Copy

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;
Copy
 COLUMN1| COLUMN2|
--------+--------+
       1|	2|
       1|       2|
       2|       3|
       3|       4|
       4|       5|
       5|       6|

Copy
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;
$$;
Copy
             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|

Copy

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;
Copy
 COLUMN1| COLUMN2|
--------+--------+
   54321|	2|

Copy
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;
$$;
Copy
ambiguous column name 'COLUMN2'

Copy

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;
Copy
no data found

Copy
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;
$$;
Copy
Query produced no results

Copy

Problèmes connus

Aucun problème n’a été constaté.

EWIs connexes

  1. SSC-EWI-0030 : L’instruction ci-dessous a des utilisations de SQL dynamique.

  2. SSC-EWI-0036 : Type de données converti en un autre type de données.

  3. SSC-EWI-0058 : La fonctionnalité n’est pas prise en charge actuellement par Snowflake Scripting.

  4. SSC-EWI-0062 : L’utilisation du type personnalisé a été modifiée en variante.

  5. SSC-EWI-OR0129 : L’attribut TYPE n’a pas pu être résolu.

  6. SSC-FDM-0006 : La colonne de type nombre peut ne pas se comporter de la même manière dans Snowflake.

  7. SSC-FDM-OR0031: La clause de connexion des erreurs dans les instructions DML n’est pas prise en charge par Snowflake.

  8. SSC-PRF-0001 : Cette instruction a des utilisations d’opérations de curseur fetch bulk.

  9. SSC-PRF-0003 : Fetch à l’intérieur d’une boucle est considéré comme un modèle complexe, ce qui pourrait dégrader les performances de Snowflake.

LOOP

Description

À chaque itération de l’instruction de base LOOP, ses instructions s’exécutent et le contrôle revient au début de la boucle. L’instruction LOOP se termine lorsqu’une instruction à l’intérieur de la boucle transfère le contrôle à l’extérieur de la boucle ou lève une exception.\ (Référence linguistique Oracle PL/SQL Instruction BASIC LOOP)

 LOOP statement... END LOOP [ label ] ;
Copy
 LOOP
  <statement>;
  [ <statement>; ... ]
END LOOP [ <label> ] ;
Copy

Le comportement d’Oracle BASIC LOOP peut également être modifié à l’aide des instructions :

Modèles d’échantillons de sources

Cas simple de Loop

Ce cas est équivalent sur le plan fonctionnel.

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;
Copy
ITERATOR|
--------+
1       |
2       |
3       |
4       |
5       |
6       |
7       |
8       |
9       |

Copy
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;
Copy
ITERATOR|
--------+
1       |
2       |
3       |
4       |
5       |
6       |
7       |
8       |
9       |

Copy

Known Issues

Aucun problème n’a été constaté.

Related EWIs

Pas d’EWIs connexes.

OUTPUT PARAMETERS

Description

Un paramètre de sortie est un paramètre dont la valeur est transmise à l’extérieur du module de procédure stockée/fonction, vers le bloc appelant PL/SQL. Les paramètres de sortie n’étant pas pris en charge par le support Snowflake Scripting, une solution a été mise en œuvre afin d’émuler leur fonctionnalité.

Sample Source Patterns

Échantillon de table auxiliaire

 CREATE TABLE table01 (col1 NUMBER, col2 NUMBER);
Copy
 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"}}'
;
Copy

Dans la déclaration, les mots-clés OUT ou IN OUT sont supprimés. L’affectation est émise de la même manière que l’entrée, mais pour émuler la fonctionnalité du paramètre de sortie, certaines instructions sont ajoutées.

Lorsqu’une procédure avec des paramètres de sortie est appelée dans une autre procédure, certaines instructions sont ajoutées afin d’obtenir et d’attribuer la ou les valeurs aux arguments respectifs.

Paramètre unique Out

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;
Copy
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;
$$;
Copy

Plusieurs paramètres Out

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;
Copy
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;
$$;
Copy

Afin de vérifier que la fonctionnalité est correctement émulée, la requête suivante va exécuter la procédure et un SELECT à partir de la table mentionnée précédemment.

Oracle
 CALL proc_with_single_output_parameters();
CALL proc_with_multiple_output_parameters();

SELECT * FROM table01;
Copy
COL1|COL2
----+----
123 |-1
123 |456


Copy
Snowflake Scripting
 CALL proc_with_single_output_parameters();
CALL proc_with_multiple_output_parameters();

SELECT * FROM table01;
Copy
COL1                   | COL2
-----------------------+-----------------------
123.000000000000000000 | -1
123.000000000000000000 | 456.000000000000000000

Copy

Paramètres OUT du type de données de client

lorsque le paramètre de sortie est un type de client, le processus est similaire à celui d’un type de données ordinaire.

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;
Copy
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;
$$;
Copy

Known Issues

1. Procedures with output parameters inside packages may not work correctly

Actuellement, il y a un problème de collecte des informations sémantiques des procédures qui résident à l’intérieur des paquets, ce qui explique pourquoi la transformation des paramètres de sortie peut fonctionner partiellement ou ne pas fonctionner du tout. Cette question fait déjà l’objet d’un document de travail.

2. Some data types may not work properly

Comme le montre la transformation, lorsqu’on récupère la valeur à partir des procédures appelées, une conversion implicite est effectuée de VARIANT vers le type spécifié par la variable. Comme il existe de nombreux types de données possibles, certaines transformations peuvent échouer ou contenir des données différentes.

Related EWIs

  1. SSC-FDM-0006 : La colonne de type nombre peut ne pas se comporter de la même manière dans Snowflake.

  2. SSC-FDM-0007 : Élément avec des dépendances manquantes.

  3. SSC-FDM-0015 : Type de données non reconnu.

PROCEDURE CALL

Note

Certaines parties du code de sortie sont omises pour des raisons de clarté.

Description

Cette section décrit la syntaxe des invocations de sous-programmes à l’intérieur des blocs PL, tels que les procédures ou les blocs anonymes.

Pour plus d’informations à ce sujet, veuillez vous référer à la documentation Oracle sur les sous-programmes : (Référence linguistique Oracle PL/SQL Instruction d’invocation de sous-programme)

Les appels de procédure peuvent être migrés vers Snowflake tant qu’il n’y a pas de paramètres optionnels et que leur ordre correspond aux paramètres formels. Veuillez noter que les invocations de procédures sont transférées vers une instruction Call.

 <subprogram invocation> := subprogram_name [ ( [ parameter [, parameter]... ] ) ]

<parameter> := {
  <actual parameter>
  | <formal parameter name> => <actual parameter>
  }
Copy

Snowflake Scripting prend en charge cette instruction, avec toutefois quelques différences fonctionnelles.

 <subprogram invocation> := CALL subprogram_name [ ( [ parameter [, parameter]... ] ) ]

<parameter> := {
  <actual parameter>
  | <formal parameter name> => <actual parameter>
  }
Copy

Modèles d’échantillons de sources

Note

Examinez la table et la procédure suivantes pour les exemples ci-dessous.

 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;
Copy
 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;
$$;
Copy

Appel simple

Oracle
 CREATE OR REPLACE PROCEDURE simple_calling_procedure
AS
BEGIN
    called_procedure(1);
END;

CALL simple_calling_procedure();

SELECT * FROM procedure_call_test_table;
Copy
COL1|
----+
   1|

Copy
Exécution de scripts 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;
Copy
COL1|
----+
   1|

Copy

Appel d’une procédure avec un paramètre facultatif

Avertissement

Cet échantillon contient une intervention manuelle pour certaines différences fonctionnelles et sert à les expliquer. Pour plus d’informations sur ces différences, veuillez consulter la section Problèmes connus ci-dessous.

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;
Copy
COL1|
----+
   1|
   2|
   3|
   4|
   5|
   6|
   7|
   8|
   9|
  10|
  11|
  12|

Copy
Exécution de scripts 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;
Copy
COL1|
----+
   1|
   2|
   3|
   4|
   5|
   6|
   7|
   8|
   9|
  10|
  11|
  12|

Copy

Problèmes connus

1. Calling Subprograms with default values is not supported

Snowflake ne prend pas en charge l’ensemble des valeurs par défaut des paramètres. Ceux-ci devront donc être renseignés à chaque appel.

2. Named parameters are accepted, but not functionally equivalent

Ces paramètres ne provoqueront aucune erreur de compilation lorsqu’ils seront exécutés dans Snowflake ; cependant, les appels les placent toujours de manière positionnelle. C’est pourquoi il convient de vérifier l’ordre de ces paramètres. SnowConvert ne permet pas de vérifier ni de réordonner ces paramètres.

3. Calling Subprograms with Out Parameters is not supported

Snowflake ne prend pas en charge les modes de paramètres, mais une solution est en cours d’implémentation pour émuler leur fonctionnalité. Pour obtenir plus d’informations sur la transformation des paramètres de sortie, veuillez consulter l’article suivant : Paramètres de sortie.

EWIs connexes

  1. SSC-EWI-0002 : Les paramètres par défaut peuvent avoir besoin d’être réorganisés.

  2. SSC-FDM-0007 : Élément avec des dépendances manquantes.

RAISE

Description

L’instruction RAISE lève explicitement une exception.

En dehors d’un gestionnaire d’exception, vous devez spécifier le nom de l’exception. À l’intérieur d’un gestionnaire d’exception, si vous omettez le nom de l’exception, l’instruction RAISE lève à nouveau l’exception en cours. (Référence linguistique PL/SQL Instruction Raise)

L’instruction est entièrement prise en charge par Snowflake Scripting, mais tenez compte du fait qu’il peut y avoir des différences entre l’instruction Commit et l’instruction Rollback.

 RAISE <exception_name> ;
Copy

Snowflake Scripting prend en charge cette instruction.

 RAISE <exception_name> ;
Copy

Modèles d’échantillons de sources

Levée d’exception simple

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);
Copy
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.

Copy
Exécution de scripts 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);
Copy
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

Copy

Problèmes connus

Aucun problème n’a été constaté.

EWIs connexes

Pas d’EWIs connexes.

RAISE_APPICATION_ERROR

Description générale

La procédure RAISE_APPLICATION_ERROR vous permet d’émettre des messages d’erreur définis par l’utilisateur ORA- à partir de sous-programmes stockés. Ainsi, vous pouvez signaler les erreurs à votre application et éviter de renvoyer des exceptions non gérées (Documentation Oracle).

Syntaxe Oracle

 raise_application_error(
      error_number, message[, {TRUE | FALSE}]);
Copy

Note

error_number est un entier négatif compris entre -20000 .. -20999 et message est une chaîne de caractères d’une longueur maximale de 2048 octets.

Si le troisième paramètre facultatif est TRUE, l’erreur est placée sur la pile des erreurs précédentes. Si le paramètre est FALSE (valeur par défaut), l’erreur remplace toutes les erreurs précédentes.

L’instruction équivalente dans Snowflake est la clause RAISE. Néanmoins, il est exigé de déclarer l’exception définie par l’utilisateur en tant que variable avant d’appeler l’instruction RAISE pour celle-ci.

Syntaxe Snowflake

 <exception_name> EXCEPTION [ ( <exception_number> , '<exception_message>' ) ] ;
Copy

Note

Pour plus d’informations, consultez la documentation Snowflake.

Modèles d’échantillons de sources

1. Exception in functions without declaring section

Dans ce scénario, la fonction sans section de déclaration est traduite en procédure avec la déclaration d’exception. Veuillez noter que :

  • Le nom de la variable d’exception est déclaré en casse majuscule.

  • Le nom de la variable d’exception est basé sur la description et une terminaison est composée d’un nom de code d’exception suivi d’un numéro consécutif.

  • La section de déclaration est créée même si la fonction ou la procédure initiale ne la contient pas.

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;
Copy
ORA-20001: First exception message

Copy

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;
$$;
Copy
FIRST EXCEPTION MESSAGE

Copy

2. Exception code number outside limits

L’exemple suivant montre la traduction commentée dans le corps de la procédure. C’est parce que le code est en dehors des limites applicables à Snowflake. La solution consiste à remplacer le code d’exception par un code disponible dans la section des requêtes.

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;
Copy
ORA-20000: My exception message

Copy

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;
$$;
Copy
 Invalid error code '-20,000'. Must be between -20,999 and -20,000

Copy

3. Exception stack functionality

La fonctionnalité de la pile d’exceptions n’est pas prise en charge dans Snowflake et est supprimée de la déclaration d’exception.

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;
Copy
ORA-20001: My exception message

Copy

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;
$$;
Copy
MY EXCEPTION MESSAGE

Copy

4. Multiple exceptions with the same exception code

Plusieurs exceptions identiques peuvent coexister dans la section de déclaration et dans les instructions raise.

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;
Copy
ORA-20000: The first exception

Copy

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;
$$;
Copy
THE FIRST EXCEPTION

Copy

Problèmes connus

  1. La fonction SQLREM peut être réexaminée.

  2. Le numéro de code d’exception en dehors des limites applicables dans Snowflake doit être modifié en un code d’exception disponible.

  3. L’ajout à une pile d’erreurs n’est pas pris en charge.

EWIs connexes

  1. SSC-EWI-OR0099 : Le code d’exception dépasse la limite de Snowflake Scripting.

  2. SSC-FDM-0029 : Une fonction définie par l’utilisateur a été transformée en procédure Snowflake.

  3. SSC-FDM-OR0011 : L’argument booléen a été supprimé car l’option « add to stack » n’est pas prise en charge.

UDF CALL

Note

Certaines parties du code de sortie sont omises pour des raisons de clarté.

Description

Comme cela est largement reconnu, les fonctions définies par l’utilisateur non scalaires (UDFs) dans Oracle sont converties en procédures stockées Snowflake pour prendre en charge des fonctionnalités plus complexes.

Cette transformation modifie également la manière dont la fonction est invoquée, passant d’un appel de fonction traditionnel à un appel de procédure stockée.

Pour plus de détails concernant l’invocation des procédures stockées, référez-vous à la documentation accessible ici : PROCEDURE CALL.

Modèles d’échantillons de sources

Note

Considérez la fonction et les tables suivantes pour les exemples ci-dessous.

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)
);
Copy
 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" }}'
;
Copy

Appel d’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;
Copy
ID	RESULT_COL
1	8

Copy
Exécution de scripts 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;
Copy
ID	RESULT_COL
1	8

Copy

Appel d’UDF dans une requête

Lorsqu’un appel de fonction est intégré à une requête, le processus d’invocation devient plus complexe en raison de la limite imposée par Snowflake, qui ne permet pas d’appeler des procédures directement dans les requêtes. Pour surmonter cette limite, l’invocation de la procédure est déplacée en dehors de la requête, et le résultat est assigné à une variable. Cette variable est ensuite référencée dans la requête, ce qui permet d’obtenir une équivalence fonctionnelle. Cette approche permet l’exécution de comportements plus complexes dans le cadre des requêtes Snowflake tout en respectant les contraintes procédurales.

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;
Copy
ID	RESULT_COL
1	6
2       7

Copy
Exécution de scripts 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;
Copy
ID	RESULT_COL
1	6
2       7

Copy

Problèmes connus

1. Unsupported Usage of UDFs in Queries with Query Dependencies

Lors de l’appel de fonctions définies par l’utilisateur (UDFs) dans des requêtes avec des dépendances de requête, les scénarios impliquant des fonctions intégrées avec des colonnes comme arguments ne sont pas pris en charge. Cette limite est due au fait que les valeurs des colonnes ne sont pas accessibles depuis l’extérieur de la requête. Voici quelques exemples de scénarios non pris en charge :

 BEGIN
    SELECT
        sum_to_varchar_function(ext.col1, ext.col2) -- columns as arguments not supported
    INTO
        result_value
    FROM example_table ext;
END;
Copy

\ Les scénarios pris en charge incluent les appels de fonctions avec d’autres types d’arguments tels que des valeurs littérales, des variables externes ou des paramètres. Par exemple :

 BEGIN
    SELECT
        sum_to_varchar_function(100, param1)
    INTO
        result_value
    FROM example_table ext;
END;
Copy

Dans les scénarios pris en charge, la fonction peut effectivement être migrée.

EWIs connexes

  1. SSC-EWI-0073 : En attente de l’examen de l’équivalence fonctionnelle.

  2. SSC-FDM-0006 : La colonne de type nombre peut ne pas se comporter de la même manière dans Snowflake.

  3. SSC-FDM-0029 : Une fonction définie par l’utilisateur a été transformée en procédure Snowflake.

WHILE

Description

L’instruction WHILE LOOP exécute une ou plusieurs instructions alors qu’une condition est TRUE. \ (Référence linguistique Oracle PL/SQL Instruction WHILE)

 WHILE boolean_expression
  LOOP statement... END LOOP [ label ] ;
Copy
 WHILE ( <condition> ) { DO | LOOP }
  <statement>;
  [ <statement>; ... ]
END { WHILE | LOOP } [ <label> ] ;
Copy

Le comportement d’Oracle WHILE peut également être modifié à l’aide des instructions :

Modèles d’échantillons de sources

Cas simple While

Ce cas est équivalent sur le plan fonctionnel.

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;
Copy
ITERATOR|
--------+
1       |
2       |
3       |
4       |
5       |
6       |
7       |
8       |
9       |

Copy
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;
Copy
ITERATOR|
--------+
1       |
2       |
3       |
4       |
5       |
6       |
7       |
8       |
9       |

Copy

Known Issues

Aucun problème n’a été constaté.

Related EWIs

Pas d’EWIs connexes.

CURSOR

Description

Note

Pour plus d’informations concernant la déclaration du curseur, cliquez ici.

Cette section couvre la référence de traduction pour le curseur explicite Oracle. Les variables de curseur Oracle n’ont pas d’équivalent dans Snowflake Scripting.

Note

Certaines parties du code de sortie sont omises pour des raisons de clarté.

Les curseurs sont des pointeurs qui permettent aux utilisateurs de parcourir les résultats des requêtes. Pour plus d’informations sur les curseurs Oracle, cliquez ici.

Définition du curseur

 CURSOR cursor
 [ ( cursor_parameter_dec [, cursor_parameter_dec ]... )]
   [ RETURN rowtype] IS select_statement ;
Copy

Curseur Open

 OPEN cursor [ ( cursor_parameter [ [,] actual_cursor_parameter ]... ) ] ;
Copy

Curseur Fetch

 FETCH { cursor | cursor_variable | :host_cursor_variable }
  { into_clause | bulk_collect_into_clause [ LIMIT numeric_expression ] } ;
Copy

Curseur Close

 CLOSE { cursor | cursor_variable | :host_cursor_variable } ;
Copy

Attributs du curseur

 named_cursor%{ ISOPEN | FOUND | NOTFOUND | ROWCOUNT }
Copy

Curseur FOR Loop

 [ FOR record IN
  { cursor [ ( cursor_parameter_dec
               [ [,] cursor_parameter_dec ]... )]
  | ( select_statement )
  }
    LOOP statement... END LOOP [label] ;
Copy

Snowflake Scripting prend en charge les curseurs, mais ses fonctionnalités sont moindres que celles d’Oracle. Pour plus d’informations sur ces curseurs, cliquez ici.

Déclaration de curseurs

 <cursor_name> CURSOR FOR <query>
Copy

Curseur Open

 OPEN <cursor_name> [ USING (bind_variable_1 [, bind_variable_2 ...] ) ] ;
Copy

Curseur Fetch

 FETCH <cursor_name> INTO <variable> [, <variable> ... ] ;
Copy

Curseur Close

 CLOSE <cursor_name> ;
Copy

Curseur FOR Loop

 FOR <row_variable> IN <cursor_name> DO
    statement;
    [ statement; ... ]
END FOR [ <label> ] ;
Copy

Modèles d’échantillons de sources

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;
Copy
 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;
$$;
Copy

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;
Copy
 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;
$$;
Copy

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;
Copy
 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;
$$;
Copy

4. Parameterized Cursor

Vous pouvez utiliser « ? » Dans la condition de filtre du curseur, dans la section de déclaration, définissez la variable de liaison. Lors de l’ouverture du curseur, nous pouvons ajouter la syntaxe supplémentaire « USING <bind_variable_1 > » pour passer la variable de liaison.

Vous trouverez ci-dessous quelques exemples de scénarios qui peuvent se produire lors de l’utilisation de paramètres dans les curseurs :

4.1 Exemple paramétré de curseur de base
 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;
Copy
 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;
$$;
Copy
4.2 Curseurs paramétrés avec plusieurs paramètres d’envoi
 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;
Copy
 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;
$$;
Copy
4.3 Curseurs paramétrés avec utilisation de paramètres de procédure dans la requête
 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);
Copy
 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);
Copy

5. Using Cursors In Fetch And For Loop

Les curseurs peuvent être contrôlés à l’aide de l’instruction FOR, ce qui permet de traiter chaque enregistrement d’un curseur pendant que l’instruction FETCH place, enregistrement par enregistrement, les valeurs retournées par le curseur dans un ensemble de variables, qui peuvent être des enregistrements PLSQL

5.1 Curseurs 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;
Copy
 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;
$$;
Copy
5.2 Curseurs 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;
Copy
 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;
$$;
Copy

Problèmes connus

1. RETURN clause is not supported in Snowflake Scripting Cursor Declaration

La déclaration de curseur pour Snowflake Scripting n’inclut pas cette clause. Elle peut être supprimée de la définition du curseur Oracle pour obtenir une équivalence fonctionnelle.

2. OPEN statement cannot pass values for declared arguments

Même si des arguments peuvent être déclarés pour un curseur, leurs valeurs ne peuvent pas être affectées dans Snowflake Scripting. La meilleure alternative consiste à utiliser la clause USING avec des variables de liaison.

3. FETCH statement cannot use records

Snowflake Scripting ne prend pas en charge les enregistrements. Il est toutefois possible de les migrer en utilisant le type de données OBJECT et la méthode OBJECT_CONSTRUCT(). Pour plus d’informations, veuillez consulter la section Définition du type d’enregistrement.

4. FETCH BULK COLLECT INTO clause is not supported in Snowflake Scripting

Snowflake Scripting ne prend pas en charge la clause BULK COLLECT INTO. Cependant, il est possible d’utiliser ARRAY_AGG avec une table temporelle pour construire une nouvelle variable avec les données correspondant à l’information du curseur. Pour plus d’informations, veuillez consulter la section Opérations en masse de collection.

5. Cursor attributes do not exist in Snowflake Scripting

Les curseurs Oracle ont différents attributs qui permettent à l’utilisateur de vérifier leur statut, par exemple s’ils sont ouverts ou le nombre de lignes extraites. Cependant, ces attributs concernant le statut du curseur n’existent pas dans Snowflake Scripting.

6. The cursor’s query does not have access to the procedure’s variables and parameters

Dans Oracle, la requête dans la déclaration du curseur a accès aux variables et paramètres de la procédure, mais dans Snowflake Scripting, ce n’est pas le cas. L’autre solution consiste à utiliser la clause USING avec des variables de liaison. Pour plus d’informations, consultez cette section.

7. %NOTFOUND attribute is not supported in Snowflake Scripting Cursor

Dans Oracle, il est possible d’utiliser, avant la première extraction d’un curseur ouvert, curseur_name%NOTFOUND qui renvoie TRUE si la dernière extraction n’a pas renvoyé de ligne, ou FALSE si la dernière extraction a renvoyé une ligne. Snowflake Scripting ne prend pas en charge l’utilisation de cet attribut ; en revanche, il peut être validé si la variable assignée au résultat du curseur contient des valeurs

EWIs connexes

  1. SSC-EWI-0036 : Type de données converti en un autre type de données.

  2. SSC-EWI-OR0002 : Colonnes de l’expression non trouvées.

  3. SSC-EWI-OR0036 : Problèmes de résolution de types, l’opération arithmétique peut ne pas se comporter correctement entre une chaîne et une date.

  4. SSC-PRF-0003 : Fetch à l’intérieur d’une boucle est considéré comme un modèle complexe, ce qui pourrait dégrader les performances de Snowflake.

  5. SSC-PRF-0004 : Cette instruction utilise le curseur for loop.

CURSOR DECLARATION

Note

Instruction non pertinente.

Avertissement

Remarquez que cette instruction est retirée de la migration parce qu’il s’agit d’une syntaxe non pertinente. Cela signifie qu’elle n’est pas exigée dans Snowflake.

Note

Certaines parties du code de sortie sont omises pour des raisons de clarté.

Description

Cette section explique la traduction de la déclaration des curseurs dans Oracle. Pour plus d’informations, consultez la documentation suivante sur les procédures et les curseurs dans Oracle.

Modèles d’échantillons de sources

CURSOR DECLARATION

Notez que dans cet exemple, l’instruction CURSOR a été supprimée. Il s’agit d’une syntaxe non pertinente dans la transformation ciblée sur Snowflake.

 CREATE PROCEDURE PROC_COLLECTIONS
AS
CURSOR C2 RETURN T1%TYPE;
BEGIN
    NULL;
END
Copy
 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;
$$;
Copy

Problèmes connus

Aucun problème n’a été constaté.

EWIs connexes

Pas d’EWIs connexes.

Variables de curseur

Note

Certaines parties du code de sortie sont omises pour des raisons de clarté.

Description

Une variable de curseur est comme un curseur explicite qui n’est pas limité à une seule requête.

(Référence linguistique Oracle PL/SQL Déclaration de variable de curseur)

Définition du type de curseur Ref

 TYPE type IS REF CURSOR
  [ RETURN
    { {db_table_or_view | cursor | cursor_variable}%ROWTYPE
    | record%TYPE
    | record_type
    | ref_cursor_type
    }
  ] ;
Copy

Déclaration des variables de curseur

 cursor_variable type;
Copy

Instruction OPEN FOR

 OPEN { cursor_variable | :host_cursor_variable}
  FOR select_statement [ using_clause ] ;
Copy

Avertissement

Snowflake Scripting n’a pas d’équivalence directe avec les variables de curseur et l’instruction OPEN FOR, mais il est possible de les émuler avec différentes solutions de contournement pour obtenir une équivalence fonctionnelle.

Modèles d’échantillons de sources

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;
Copy
 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;
$$;
Copy

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;
Copy
 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;
$$;
Copy

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;
Copy
 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;
$$;
Copy

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;
Copy
 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;
$$;
Copy

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;
Copy
 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;
$$;
Copy

Problèmes connus

Aucun problème n’a été constaté.

EWIs connexes

  1. SSC-EWI-0030 : L’instruction ci-dessous a des utilisations de SQL dynamique.

  2. SSC-EWI-0058 : La fonctionnalité n’est pas prise en charge actuellement par Snowflake Scripting.

PARAMETRIZED CURSOR

Note

Certaines parties du code de sortie sont omises pour des raisons de clarté.

Description

Oracle prend en charge les paramètres pour les curseurs déclarés. Cependant, le support Snowflake Scripting ne prend pas en charge cette fonction, de sorte que la déclaration et l’utilisation du curseur ne sont pas possibles.

Exemple de code

Code d’entrée 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;
Copy
Code de sortie :
 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;
$$;
Copy

Recommandations

  • Essayez d’utiliser des liens pour la requête dans le curseur et ouvrez le curseur avec la clause USING. Gardez à l’esprit qu’un paramètre utilisé plusieurs fois sur un même curseur peut nécessiter de passer la variable plusieurs fois dans la clause USING.

 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;
$$;
Copy
  • Modifiez manuellement le curseur pour utiliser les liaisons.

  • Si vous avez encore besoin d’aide, vous pouvez nous envoyer un e-mail à l’adresse suivante : snowconvert-support@snowflake.com

EWIs connexes

  1. SSC-PRF-0004 : Cette instruction utilise le curseur for loop.

Solution de contournement pour les curseurs utilisant des paramètres ou des variables de procédure

Description

Cette section décrit comment simuler l’utilisation des paramètres du curseur et des variables de procédure dans la requête d’un curseur. Le nom des variables ou des paramètres est remplacé par des liaisons à l’aide du signe ?. Ensuite, lorsque le curseur est ouvert, les valeurs doivent être transmises avec la clause USING.

Note

Some parts in the output code are omitted for clarity reasons.

Copy

Curseur avec variables locales

Utilisez des liaisons pour la requête dans le curseur pour la variable ou le paramètre de procédure utilisé et ouvrez le curseur avec la clause 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;
Copy
 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;
$$;
Copy

Curseur avec paramètres

Utilisez des liaisons pour la requête dans le curseur pour chaque paramètre utilisé et ouvrez le curseur avec la clause USING. Gardez à l’esprit qu’un paramètre utilisé plusieurs fois sur un même curseur peut nécessiter de passer la variable plusieurs fois dans la clause 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;
Copy
 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;
$$;
Copy

EWIs connexes

  1. SSC-PRF-0004 : Cette instruction utilise le curseur for loop

CREATE FUNCTION

Description

Note

Certaines parties du code de sortie sont omises pour des raisons de clarté.

Une fonction stockée (également appelée fonction utilisateur ou fonction définie par l’utilisateur) est un ensemble d’instructions PL/SQL que vous pouvez appeler par leur nom. Les fonctions stockées sont très similaires aux procédures, à l’exception du fait qu’une fonction renvoie une valeur à l’environnement dans lequel elle est appelée. Les fonctions utilisateur peuvent être utilisées dans le cadre d’une expression SQL.

Une spécification d’appel déclare une méthode Java ou une routine en langue de troisième génération (3GL) afin qu’elle puisse être appelée à partir de PL/SQL. Vous pouvez également utiliser l’instruction CALL SQL pour appeler une telle méthode ou routine. La spécification d’appel indique à la base de données Oracle quelle méthode Java, ou quelle fonction nommée dans quelle bibliothèque partagée, doit être invoquée lors d’un appel. Elle indique également à la base de données les conversions de type à effectuer pour les arguments et la valeur de retour. Référence linguistique Oracle SQL Create Function.

Syntaxe Oracle

Pour plus d’informations sur Oracle Create Function, cliquez ici.

 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 } } ;
Copy

Syntaxe Snowflake

Snowflake permet l’utilisation de 3 langues différentes dans les fonctions définies par l’utilisateur :

  • SQL

  • JavaScript

  • Java

Pour l’instant, SnowConvert ne prend en charge que les langues cibles SQL et JavaScript.

Pour plus d’informations sur Snowflake Create Function, cliquez ici.

Note

Les fonctions SQL définies par l’utilisateur n’acceptent qu’une seule requête comme corps. Ils peuvent lire dans la base de données mais ne sont pas autorisés à y écrire ou à la modifier (UDFs SQL scalaires).

 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>'
Copy

Note

Les fonctions définies par l’utilisateur JavaScript autorisent plusieurs instructions dans leur corps, mais ne peuvent pas effectuer de requêtes dans la base de données. (UDFs JavaScript scalaires).

 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>'
Copy

Modèles d’échantillons de sources

Exemple de données auxiliaires

Note

Ce code a été exécuté pour une meilleure compréhension des exemples :

 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'));
Copy
 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'));
Copy

Problèmes connus

Aucun problème n’a été constaté.

connexesEWIS

  1. SSC-FDM-OR0042 : Le type de date transformé en horodatage a un comportement différent

Curseur pour une variable de retour

Note

Certaines parties du code de sortie sont omises pour des raisons de clarté.

Ce modèle définit une fonction dans Oracle PL/SQL qui utilise un curseur pour récupérer une valeur unique et la renvoyer.

Composants :

  1. Déclaration de fonction :

    • CREATE FUNCTION functionName(parameters) RETURN returnType

    • Déclare la fonction avec les paramètres d’entrée et le type de retour.

  2. Déclarations de variables :

    • Déclare les variables, y compris la variable de retour.

  3. Déclaration de curseurs :

    • CURSOR cursorName IS SELECT singleColumn FROM ... WHERE ... [AND col1 = localVar1];

    • Définit un curseur permettant de sélectionner une seule colonne dans une table avec des conditions de filtrage facultatives.

  4. Bloc BEGIN-END :

    • Affectation des variables.

    • Ouvre le curseur.

    • Récupère le résultat dans la variable de retour.

    • Ferme le curseur.

    • Renvoie la valeur retournée.

Dans ce cas, les variables sont transformées en une expression de table commune (CTE). Ainsi que la requête dans le curseur à laquelle, en outre, la clause FETCH FIRST 1 ROW ONLY est ajoutée pour simuler le comportement de FETCH CURSOR.

L’instruction RETURN est transformée en sélection finale.

Requêtes

 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;
Copy
 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
$$;
Copy
FUNC1()          | 
-----------------+ 
2004-05-03.      |

Copy
 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;
Copy
 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
$$;
Copy
FUNC1()          | 
-----------------+ 
2004-05-03.      |

Copy

Problèmes connus

Aucun problème n’a été constaté.

connexesEWIS

  1. SSC-FDM-OR0042 : Le type de date transformé en horodatage a un comportement différent.

  2. SSC-EWI-0073 : En attente de l’examen de l’équivalence fonctionnelle.

Curseur avec instruction IF

Note

Certaines parties du code de sortie sont omises pour des raisons de clarté.

Ce modèle définit une fonction qui utilise conditionnellement un curseur pour rechercher et renvoyer une valeur en fonction d’une instruction IF.

Composants :

  1. Déclaration de fonction :

    • CREATE FUNCTION functionName(parameters) RETURN returnType

    • Déclare la fonction avec les paramètres d’entrée et le type de retour.

  2. Déclaration de curseurs :

    • CURSOR cursorName IS SELECT singleColumn FROM ... WHERE ... [AND col1 = localVar1];

    • Définit un curseur permettant de sélectionner une seule colonne dans une table avec des conditions de filtrage facultatives.

  3. Déclaration de variables :

    • Déclare les variables, y compris la variable de retour.

  4. Bloc BEGIN-END avec instruction IF :

    • Affectation des variables.

    • Vérifier si une condition est vraie.

    • Si true, ouvre le curseur, récupère le résultat dans la variable de retour, ferme le curseur et renvoie la valeur récupérée. (Le curseur peut également être ouvert dans le bloc ELSE et doit répondre aux mêmes conditions)

    • Le bloc ELSE est facultatif. S’il existe, il ne doit contenir qu’une seule instruction qui peut être une affectation ou une instruction RETURN.

Les variables sont transformées en une expression de table commune (CTE). Ainsi que la requête dans le curseur à laquelle, en outre, la clause FETCH FIRST 1 ROW ONLY est ajoutée pour simuler le comportement de FETCH CURSOR.

L'instruction IF/ELSE peut être traitée en utilisant CASE EXPRESSION à l’intérieur de la sélection, ce qui permet d’insérer des conditions dans les requêtes. L’instruction RETURN est transformée en sélection finale.

Requêtes

 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;
Copy
 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
$$;
Copy
FUNC2(0)      |
--------------+
NULL          |

FUNC2(1)      |
--------------+
33            |

Copy
 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;
Copy
 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
$$;
Copy
FUNC2(0)      |
--------------+
33            |

FUNC2(1)      |
--------------+
2             |

Copy
 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;
Copy
 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
$$;
Copy
FUNC2(0)      |
--------------+
0             |

FUNC2(1)      |
--------------+
33            |

Copy

Problèmes connus

Aucun problème n’a été constaté.

connexesEWIS

Pas d’EWIs connexes.

Instruction à plusieurs IFs

Ce modèle définit une fonction qui utilise des instructions conditionnelles sur des variables locales.

Composants :

  1. Déclaration de fonction :

    • CREATE FUNCTION functionName(parameters) RETURN returnType

    • Déclare la fonction avec les paramètres d’entrée et le type de retour.

  2. Déclaration de variables :

    • Déclare les variables, y compris la variable de retour.

  3. Bloc BEGIN-END avec instruction IF :

    • Vérifier si une condition est vraie.

    • Chaque cas est utilisée pour attribuer une valeur à la même variable.

Conversion :

DECLARE SECTION : les variables avec une expression par défaut sont déplacées vers une expression de table commune.

L'instruction IF/ELSE peut être traitée à l’aide de CASE EXPRESSION à l’intérieur de la sélection, ce qui permet d’introduire des conditions dans les requêtes.

L’instruction RETURN est transformée en sélection finale.

 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;
Copy
 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
$$;
Copy
 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;
Copy
 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
$$;
Copy
 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;
Copy
 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
$$;
Copy
 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;
Copy
 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
$$;
Copy

Problèmes connus

Aucun problème n’a été constaté.

connexesEWIS

  1. SSC-FDM-OR0042 : Le type de date transformé en horodatage a un comportement différent.

  2. SSC-EWI-0073 : En attente de l’examen de l’équivalence fonctionnelle.

  3. SSC-EWI-OR0036 : Problèmes de résolution de types, l’opération arithmétique peut ne pas se comporter correctement entre une chaîne et une date.

DML STATEMENTS

Description

Les extensions d’instruction DML diffèrent des instructions normales DML car elles peuvent utiliser des éléments PL/SQL tels que des collections et des enregistrements. Jusqu’à présent, certains de ces éléments n’étaient pas pris en charge par Snowflake Scripting. Si une instruction n’est pas prise en charge, une EWI sera ajoutée lors de la traduction. Les autres instructions DML seront traduites comme si elles ne se trouvaient pas à l’intérieur d’une procédure.

Les instructions suivantes sont considérées comme DML :

Une section décrit comment simuler le comportement de RECORDS et COLLECTIONS pour les instructions SELECT et INSERT :

collections-and-records

Extension de l’instruction INSERT

Note

Certaines parties du code de sortie sont omises pour des raisons de clarté.

Description

L’extension PL/SQL de l’instruction SQL INSERT vous permet de spécifier un nom d’enregistrement dans la clause values_clause de l’instruction single_table_insert au lieu de spécifier une liste de colonnes dans la clause insert_into_clause. (Référence linguistique Oracle PL/SQL Extension d’instruction INSERT)

Snowflake INSERT INTO diffère de Snowflake Scripting en ce qui concerne les contraintes sur les variables ; les noms doivent être précédés de deux points « : » afin de lier la valeur des variables.

Recommandations

Note

Ce code a été exécuté pour une meilleure compréhension des exemples :

 CREATE TABLE numbers_table(num integer, word varchar2(20));
Copy
 CREATE OR REPLACE TABLE PUBLIC.numbers_table (num integer,
word VARCHAR(20));
Copy

Cas simple d’extension d’instruction INSERT

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 ;
Copy
|NUM|WORD  |
|---|------|
|10 |ten   |
|11 |eleven|


Copy
Exécution de scripts 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;
Copy
|NUM|WORD  |
|---|------|
|10 |ten   |
|11 |eleven|


Copy

Problèmes connus

1. Records are not supported by Snowflake Scripting

Les enregistrements n’étant pas pris en charge par Snowflake Scripting, au lieu d’utiliser la clause VALUES record, il est nécessaire de la transformer en clause SELECT et de scinder les colonnes de l’enregistrement. Pour plus d’informations, veuillez consulter la section Définition de type d’enregistrement.

EWIs connexes

Pas d’EWIs connexes.

Instruction MERGE

Note

Certaines parties du code de sortie sont omises pour des raisons de clarté.

Description

L’instruction MERGE est utilisée pour sélectionner des lignes dans une ou plusieurs sources en vue de les mettre à jour ou de les insérer dans une table ou une vue. Il est possible de spécifier des conditions pour déterminer s’il faut mettre à jour ou insérer dans la table ou la vue cible. Cette instruction est un moyen pratique de combiner plusieurs opérations. Elle permet d’éviter les instructions multiples INSERT, UPDATE et DELETE DML. MERGE est une instruction déterministe. Il n’est pas possible de mettre à jour la même ligne de la table cible plusieurs fois dans la même instruction MERGE. (Référence linguistique Oracle PL/SQL Instruction MERGE))

 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
Copy
 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> [ , ... ] )
Copy

Modèles d’échantillons de sources

Exemple de données auxiliaires

Note

Ce code a été exécuté pour une meilleure compréhension des exemples :

 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
    );
Copy
 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
);
Copy

Cas simple d’instruction 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;
Copy
PERSON_ID|FIRST_NAME|LAST_NAME|TITLE|
---------+----------+---------+-----+
        1|John      |Smith    |Mr   |
        2|Alice     |Jones    |Mrs. |
        3|Jane      |Doe      |Miss |
        4|Dave      |Brown    |Mr   |

Copy
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;
Copy
PERSON_ID|FIRST_NAME|LAST_NAME|TITLE|
---------+----------+---------+-----+
        1|John      |Smith    |Mr   |
        2|Alice     |Jones    |Mrs. |
        3|Jane      |Doe      |Miss |
        4|Dave      |Brown    |Mr   |

Copy

Instruction MERGE avec DELETE et clause where

Afin de trouver une équivalence entre l’instruction DELETE et la clause where, il est nécessaire de réorganiser et de mettre en œuvre certains changements dans l’instruction de fusion Snowflake.

Modification requise :
  • Remplacez la clause Oracle DELETE where_clause par une nouvelle clause Snowflake matchedClause avec l’instruction AND predicate

  • Remplacez la where_clause de Oracle merge_insert_clause par une instruction AND predicate dans 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;
Copy
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|

Copy
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;
Copy
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|

Copy

Avertissement

Dans certains cas, les modifications appliquées peuvent ne pas fonctionner comme prévu, comme dans l’exemple suivant :

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;
Copy
PERSON_ID|FIRST_NAME|LAST_NAME|TITLE|
---------+----------+---------+-----+
        1|John      |Smith    |Mr   |
        4|Dave      |Brown    |Mr   |

Copy
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;
Copy
PERSON_ID|FIRST_NAME|LAST_NAME|TITLE|
---------+----------+---------+-----+
        1|John      |Smith    |Mr   |
        2|Alice     |Jones    |Mrs. |
        4|Dave      |Brown    |Mr   |

Copy

Problèmes connus

1. Oracle’s error_logging_clause is not supported

Il n’y a pas d’équivalent pour la clause de journalisation des erreurs dans Snowflake Scripting.

2. Changed applied do not work as expected

Parfois, les modifications appliquées pour obtenir l’équivalence fonctionnelle entre l’instruction de fusion d’Oracle et celle de Snowflake ne fonctionnent pas comme prévu.

EWIs connexes

  1. SSC-FDM-0006 : La colonne de type nombre peut ne pas se comporter de la même manière dans Snowflake.

  2. SSC-FDM-OR0018 : L’instruction de fusion peut ne pas fonctionner comme prévu

Instruction SELECT INTO

Note

Certaines parties du code de sortie sont omises pour des raisons de clarté.

Description

L’instruction SELECT INTO récupère des valeurs dans une ou plusieurs tables de la base de données (comme le fait l’instruction SQL SELECT) et les stocke dans des variables (ce que ne fait pas l’instruction SQL SELECT). (Référence linguistique Oracle PL/SQL Instruction SELECT INTO)

 SELECT [ { DISTINCT | UNIQUE } | ALL ] select_list
    { into_clause | bulk_collect_into_clause } FROM rest-of-statement ;
Copy
 INTO { variable [, variable ]... | record )
Copy
 BULK COLLECT INTO { collection | :host_array }
  [, { collection | :host_array } ]...
Copy
 SELECT [ { ALL | DISTINCT } ]
    {
          [{<object_name>|<alias>}.]*
        | [{<object_name>|<alias>}.]<col_name>
        | [{<object_name>|<alias>}.]$<col_position>
        | <expr>
        [ [ AS ] <col_alias> ]
    }
    [ , ... ]
    INTO :<variable> [, :<variable> ... ]
    [...]
Copy

Modèles d’échantillons de sources

Exemple de données auxiliaires

Note

Ce code a été exécuté pour une meilleure compréhension des exemples :

 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));
Copy
 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"}}'
;
Copy

Cas simple d’instruction SELECT INTO

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;
Copy
|AUX_NUM|AUX_WORD|
|-------|--------|
|1      |one     |

Copy
Exécution de scripts 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;
Copy
|AUX_NUM|AUX_WORD|
|-------|--------|
|1      |one     |


Copy

Problèmes connus

1. BULK COLLECT INTO is not supported

Snowflake Scripting ne prend pas en charge la clause BULK COLLECT INTO. Toutefois, il est possible d’utiliser ARRAY_AGG pour construire une nouvelle variable. Pour plus d’informations, veuillez consulter la section Opérations en masse de collection.

2. Collections and records are not supported

Snowflake Scripting ne prend pas en charge l’utilisation de collections ou d’enregistrements. Il est possible de les migrer en utilisant des types de données semi-structurées comme expliqué dans cette section.

EWIs connexes

Pas d’EWIs connexes.

Contournement pour simuler l’utilisation des enregistrements

Avertissement

Cette page est obsolète mais a été conservée à des fins de compatibilité. Si vous souhaitez consulter la section mise à jour, veuillez vous référer à Collections et enregistrements

Description

Cette section décrit comment simuler le comportement des enregistrements Oracle dans les instructions SELECT et INSERT, à l’aide de RESULTSET et CURSORS de Snowflake Scripting.

Snowflake Scripting RESULTSET et CURSOR

 <resultset_name> RESULTSET [ DEFAULT ( <query> ) ] ;

LET <resultset_name> RESULTSET [ { DEFAULT | := } ( <query> ) ] ;

LET <resultset_name> RESULTSET [ { DEFAULT | := } ( <query> ) ] ;
Copy

Recommandations

Note

Pour les exemples suivants, ce code a été exécuté pour une meilleure compréhension des exemples :

 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));
Copy
 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"}}'
;
Copy

Utilisation de RESULTSET et de curseurs au lieu d’enregistrements

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;
Copy
|AUX_NUM|AUX_WORD|
|-------|--------|
|1      |one     |

Copy
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;
Copy
 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;
$$;
Copy
|AUX_NUM|AUX_WORD|
|-------|--------|
|1      |one     |


Copy

Problèmes connus

1. Limitation in the use of RESULTSET

RESULTSET est très limité dans son utilisation. Si l’instruction table(result_scan(last_query_id())), elle doit être utilisée juste après l’exécution de la requête RESULTSET. Pour plus d’informations, consultez ce lien.

EWIs connexes

  1. SSC-EWI-0036 : Type de données converti en un autre type de données.

  2. SSC-EWI-0056 : Type de création non pris en charge.

PACKAGES

Description

Utilisez l’instruction CREATE PACKAGE pour créer la spécification d’un paquet stocké, qui est une collection encapsulée de procédures stockées, de fonctions et d’autres objets de programme stockés ensemble dans la base de données. La spécification du paquet déclare ces objets. Le corps du paquet, spécifié ultérieurement, définit ces objets. (Référence linguistique Oracle PL/SQL Instruction CREATE PACKAGE)

Snowflake n’a pas d’équivalent pour les paquets Oracle. Afin de maintenir la structure, les paquets sont transformés en schéma et tous leurs éléments sont définis à l’intérieur de celui-ci. En outre, le paquet et ses éléments sont renommés afin de préserver le nom du schéma d’origine. Pour plus d’informations sur le renommage des paquets, vous pouvez consulter la section Options de traduction des paquets.

BODY

Description

L’en-tête de PACKAGE BODY est supprimé et chaque définition de procédure ou de fonction est transformée en une fonction ou procédure autonome.

CREATE [ OR REPLACE ]
[ EDITIONABLE | NONEDITIONABLE ]
PACKAGE BODY plsql_package_body_source

Copy

Modèles d’échantillons de sources

Note

Les requêtes suivantes ont été transformées avec l’option PackagesAsSchema désactivée.

Oracle

 CREATE OR REPLACE PACKAGE BODY SCHEMA1.PKG1 AS
    PROCEDURE procedure1 AS
        BEGIN
            dbms_output.put_line('hello world');
        END;
END package1;
Copy
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;
$$;
Copy

Problèmes connus

Aucun problème n’a été constaté.

EWIs connexes

  1. SSC-FDM-OR0035 : DBMS_OUTPUT.PUTLINE vérifie la mise en œuvre de l’UDF.

Constantes

Description

PACKAGE CONSTANTS peut être déclaré soit dans la déclaration du paquet, soit dans PACKAGE BODY. Lorsqu’une constante du paquet est utilisée dans une procédure, une nouvelle variable est déclarée avec le même nom et la même valeur que la constante, de sorte que le code résultant est assez similaire à l’entrée.

constant CONSTANT datatype [NOT NULL] { := | DEFAULT } expression ;

Copy

Modèles d’échantillons de sources

Échantillon de code auxiliaire

 create table table1(id number);
Copy
 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"}}'
;
Copy
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;
Copy
|ID  |
|----|
|9999|


Copy
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;
Copy
|ID  |
|----|
|9999|


Copy

Note

Notez que la définition dePROCEDURE est supprimée car elle n’est pas nécessaire dans Snowflake.

Problèmes connus

Aucun problème n’a été constaté.

EWIs connexes

  1. SSC-FDM-0006 : La colonne de type nombre peut ne pas se comporter de la même manière dans Snowflake.

DECLARATION

Description

La déclaration est convertie en schéma, de sorte que chaque élément interne est déclaré à l’intérieur de ce schéma. Tous les éléments présents dans le paquet sont commentés à l’exception de VARIABLES qui bénéficie d’une transformation adéquate.

CREATE [ OR REPLACE ]
[ EDITIONABLE | NONEDITIONABLE ]
PACKAGE plsql_package_source

Copy

Modèles d’échantillons de sources

Note

Les requêtes suivantes ont été transformées avec l’option PackagesAsSchema désactivée.

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;
Copy
Snowflake
 CREATE SCHEMA IF NOT EXISTS SCHEMA1_PKG1
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"oracle"}}'
;
Copy

Note

Notez que les définitions de FUNCTION et PROCEDURE sont supprimées car elles ne sont pas exigées dans Snowflake.

Problèmes connus

Aucun problème n’a été constaté.

EWIs connexes

Pas d’EWIs connexes.

VARIABLES

Description

PACKAGE VARIABLES peut être déclaré soit dans la déclaration du paquet, soit dans PACKAGE BODY. En raison de leur comportement, ces variables sont converties en variables de session Snowflake, de sorte que chaque utilisation ou affectation est traduite en son équivalent dans Snowflake.

 variable datatype [ [ NOT NULL] {:= | DEFAULT} expression ] ;
Copy

Modèles d’échantillons de sources

Échantillon de code auxiliaire

 create table table1(id number);
Copy
 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"}}'
;
Copy

Déclaration de variables

Oracle
 CREATE OR REPLACE PACKAGE PKG1 AS
    package_variable NUMBER:= 100;
END PKG1;
Copy
Exécution de scripts 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);
Copy

Utilisation des variables

L’utilisation des variables de paquet est transformée en fonction Snowflake GETVARIABLE qui accède à la valeur courante d’une variable de session. Une conversion explicite est ajoutée au type de données de la variable d’origine afin de maintenir l’équivalence fonctionnelle dans les opérations où ces variables sont utilisées.

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;
Copy
|ID |
|---|
|100|


Copy
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;
Copy
|ID |
|---|
|100|


Copy

Note

Notez que la définition de PROCEDURE dans le paquet est supprimée car elle n’est pas exigée par Snowflake.

Affectation régulière de variables

Lorsqu’une variable de paquet est assignée à l’aide de l’opérateur : =, l’assignation est remplacée par une UDF SnowConvert appelée UPDATE_PACKAGE_VARIABLE_STATE qui est une abstraction de la fonction 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;
Copy
|ID |
|---|
|200|


Copy

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;
Copy
|ID |
|---|
|200|


Copy

Note

Notez que la définition de PROCEDURE dans le paquet est supprimée car elle n’est pas exigée par Snowflake.

Affectation d’une variable en tant qu’argument de sortie

Lorsqu’une variable de paquet est utilisée comme argument de sortie, une nouvelle variable est déclarée à l’intérieur de la procédure, cette variable récupère la valeur de l’argument de sortie de la procédure, puis la variable est utilisée pour mettre à jour la variable de session qui fait référence à la variable de paquet à l’aide de la méthode UPDATE_PACKAGE_VARIABLE_STATE mentionnée ci-dessus. Pour plus d’informations, consultez transformation des paramètres de sortie.

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();
Copy
|ID  |
|----|
|1000|


Copy
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();
Copy
|ID  |
|----|
|1000|


Copy

Note

Notez que la définition de PROCEDURE dans le paquet est supprimée car elle n’est pas exigée par Snowflake.

Problèmes connus

Aucun problème n’a été constaté.

EWIs connexes

  1. SSC-FDM-0006 : La colonne de type nombre peut ne pas se comporter de la même manière dans Snowflake.

COLLECTIONS AND RECORDS

Avertissement

Les informations de cette section, en cours de modification, sont sujettes à modification.

Description générale

PL/SQL vous permet de définir deux types de données composites : collection et enregistrement, où composite est un type de données qui stocke des valeurs ayant des composants internes.

Dans une collection, les composants internes ont toujours le même type de données et sont appelés éléments.

Dans un enregistrement, les composants internes peuvent avoir différents types de données et sont appelés champs. (Référence linguistique Oracle PL/SQL COLLECTIONS AND RECORDS)

Note

Tenez compte de la référence de traduction de l’instruction CREATE TYPE car certaines solutions de contournement peuvent se chevaucher et être fonctionnelles dans les deux scénarios.

Limitations

Snowflake ne prend pas en charge les types de données définis par l’utilisateur, ce qui inclut les Collections et Enregistrements PL, selon la documentation en ligne Types de données non pris en charge, mais il supporte les types de données semi-structurées, qui peuvent être utilisés pour imiter à la fois la structure de type hiérarchie de l’enregistrement et la structure d’élément des types de collection définis par l’utilisateur. C’est pourquoi il existe plusieurs types de fonctions pour lesquelles il n’existe pas de solution de contournement.

Voici les fonctions pour lesquelles la solution de contournement NO est proposée :

La taille de la variable ne peut pas dépasser 16MB

Snowflake définit la taille maximale de VARIANT, OBJECT et ARRAY sur 16MBs. Cela signifie que si un enregistrement, une collection ou tout élément de l’un ou l’autre dépasse cette taille, une erreur d’exécution se produit.

La capacité de Varray ne peut pas être limitée

Les varrays d’Oracle offrent la capacité de limiter le nombre d’éléments qu’ils contiennent. Ceci n’est pas pris en charge par Snowflake.

Solution de contournement proposée

À propos de la définition des types d’enregistrement

La solution de contournement proposée consiste à utiliser un type de données semi-structurées « OBJECT » pour imiter le type de données d’Oracle.

À propos de la définition des types de collection

Il existe deux solutions différentes qui dépendent du type de collection à migrer :

  • Il est proposé de transformer les tableaux associatifs en un type de données semi-structurées « OBJECT ».

  • Il est proposé de transformer les Varrays et les Tableaux de tables imbriquées en un type de données semi-structurées « ARRAY ».

Prise en charge actuelle de SnowConvert

La table suivante présente un résumé de la prise en charge actuellement fournie par l’outil SnowConvert. Tenez compte du fait que les traductions peuvent ne pas être définitives et qu’un travail supplémentaire peut être nécessaire.

Sub-FeatureCurrent recognition statusCurrent translation statusHas Known Workarounds
Record Type DefinitionsRecognized.Not Translated.Yes.
Associative Array Type DefinitionsNot Recognized.Not Translated.Yes.
Varray Type DefinitionsRecognized.Not Translated.Yes.
Nested Table Array Type DefinitionsRecognized.Not Translated.Yes.

Problèmes connus

1. Associate Arrays are considered a Nested Table

Pour l’instant, SnowConvert ne fait pas la différence entre un tableau associatif et une table imbriquée, ce qui signifie qu’ils sont mélangés dans les mêmes comptes d’évaluation.

EWIs connexes

Pas d’EWIs connexes.

Définition du type de tableau associatif

Avertissement

Les informations de cette section, en cours de modification, sont sujettes à modification.

Note

Certaines parties du code de sortie sont omises pour des raisons de clarté.

Description

Un tableau associatif (anciennement appelé table PL/SQL ou table index-by) est un ensemble de paires clé-valeur. Chaque clé est un index unique, utilisé pour l’emplacement de la valeur associée avec la syntaxe variable_name(index).

Le type de données de l”index peut être un type de chaîne (VARCHAR2, VARCHAR, STRING ou LONG) ou PLS_INTEGER. Les index sont stockés par ordre de tri, et non par ordre de création. Pour les types de chaînes, l’ordre de tri est déterminé par les paramètres d’initialisation NLS_SORT et NLS_COMP.

(Référence linguistique Oracle PL/SQL ASSOCIATIVE ARRAYS)

Avertissement

À ne pas confondre avec la définition du type Type de définition PL/SQL NESTED TABLE.

Pour la traduction, la définition du type est remplacée par un OBJECT Type de données semi-structurées et son utilisation est modifiée en conséquence pour toutes les opérations.

Pour définir un type de tableau associatif, la syntaxe est la suivante :

type_definition := TYPE IS TABLE OF datatype INDEX BY indexing_datatype;

indexing_datatype := { PLS_INTEGER
                     | BINARY_INTEGER
                     | string_datatype
                     }

Copy

Pour déclarer une variable de ce type :

variable_name collection_type;

Copy

Modèles d’échantillons de sources

Tableau associatif indexé 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();
Copy
DBMS OUTPUT
-----------
1
3
4
2
3

Copy
Snowflake

Veuillez noter le paramètre « true » dans le OBJECT_INSERT. Ainsi, l’élément est mis à jour s’il est déjà présent dans le tableau.

 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;
Copy
DBMS OUTPUT
-----------
1

3
4
2
3

Copy

Tableau associatif indexé numériquement

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();
Copy
DBMS OUTPUT
-----------
-1
3
-4
-2
-3

Copy
Snowflake

Veuillez noter que la valeur numérique est convertie en varchar lorsque l’opération le nécessite. En outre, notez le paramètre « true » dans OBJECT_INSERT. Ainsi, l’élément est mis à jour s’il est déjà présent dans le tableau.

 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;
Copy
DBMS OUTPUT
-----------
-1
3
-4
-2
-3

Copy

Tableau associatif à éléments numériques indexés par enregistrement

Dans ce cas, le tableau associatif est composé d’une structure d’enregistrement, et cette structure doit être préservée. À cette fin, d’autres opérations sur les insertions ont été ajoutées.

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();
Copy
DBMS OUTPUT
-----------
-1
3
-4
-2
-3

Copy
Snowflake

Dans ce scénario, l’insertion/mise à jour suppose une création automatique de l’enregistrement dans le tableau associatif, ce qui doit être pris en compte lors de la création de nouveaux enregistrements.

 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;
Copy
DBMS OUTPUT
-----------
-1
3
-4
-2
-3

Copy

Problèmes connus

1. They are currently not being recognized

SnowConvert traite ces collections comme des tableaux de tables imbriquées. Un élément de travail a été mis en place pour corriger ce problème.

EWIs connexes

Pas d’EWIs connexes.

Méthodes de collection

Avertissement

Les informations de cette section, en cours de modification, sont sujettes à modification.

Note

Certaines parties du code de sortie sont omises pour des raisons de clarté.

Description

Une méthode de collection est un sous-programme PL/SQL - soit une fonction qui renvoie des informations sur une collection, soit une procédure qui opère sur une collection. Les méthodes de collection facilitent l’utilisation des collections et la maintenance de vos applications.

(Référence linguistique Oracle PL/SQL COLLECTION METHODS)

Certaines de ces méthodes peuvent être mappées à des opérations semi-structurées natives de Snowflake. Celles qui ne le peuvent pas ou qui présentent des différences seront mappées à une implémentation d’UDF.

Prise en charge actuelle de SnowConvert

La table suivante présente un résumé de la prise en charge actuellement fournie par l’outil SnowConvert. Tenez compte du fait que les traductions peuvent ne pas être définitives et qu’un travail supplémentaire peut être nécessaire.

MethodCurrent recognition statusCurrent translation statusMapped to
DELETENot Recognized.Not Translated.UDF
TRIMNot Recognized.Not Translated.UDF (To be defined)
EXTENDNot Recognized.Not Translated.UDF
EXISTSNot Recognized.Not Translated.ARRAY_CONTAINS
FIRSTNot Recognized.Not Translated.UDF
LASTNot Recognized.Not Translated.UDF
COUNTNot Recognized.Not Translated.ARRAY_SIZE
LIMITNot Recognized.Not Translated.Not Supported.
PRIORNot Recognized.Not Translated.UDF (To be defined)
NEXTNot Recognized.Not Translated.UDF (To be defined)

Modèles d’échantillons de sources

COUNT

Cette méthode renvoie le nombre d’éléments « non définis » (à ne pas confondre avec les éléments null) dans une collection (les tables imbriquées peuvent devenir clairsemées en laissant ces éléments entre elles). Dans les tableaux associatifs, elle renvoie le nombre de clés du tableau.

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();
Copy
DBMS OUTPUT
-----------
2
3
4

Copy
Snowflake

L’équivalent du Snowflake est la méthode 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;
Copy
DBMS OUTPUT
-----------
2
3
4

Copy

EXISTS

Cette méthode renvoie un résultat positif si l’élément donné est contenu dans la collection. Dans les tableaux associatifs, il teste si la clé est contenue.

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();
Copy
DBMS OUTPUT
-----------
2
3
4

Copy
Snowflake

L’équivalent du Snowflake est la méthode ARRAY_CONTAINS. Notez que, lors de l’utilisation d’éléments Varchar, il est nécessaire d’effectuer une conversion vers 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;
Copy
DBMS OUTPUT
-----------
2
3
4

Copy

FIRST/LAST

Ces deux méthodes renvoient respectivement le premier et le dernier élément de la collection. Si la collection est vide, elle renvoie null. Cette opération est mappée à une UDF, qui sera ajoutée dans les révisions ultérieures.

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();
Copy
DBMS OUTPUT
-----------
abc
bca
             --These empty spaces are due to it evaluating to null

1
4

Copy
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;
Copy
 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]))
$$;
Copy
DBMS OUTPUT
-----------
abc
bca
             --These empty spaces are due to it evaluating to null

1
4

Copy

DELETE

Cette méthode permet de supprimer des éléments d’une collection. Il existe trois variantes possibles :

  • .DELETE supprime tous les éléments.

  • .DELETE(n) supprime l’élément dont l’index correspond à « n ».

  • .DELETE(n, m) supprime les index de « n » à « m ».

Note

Dans Oracle, l’utilisation de cette opération sur des tables imbriquées entraîne l’apparition d’éléments « non définis » à l’intérieur de ces tables en raison de leur faible densité.

Avertissement

Veuillez noter que les deuxième et troisième versions ne s’appliquent pas aux Varrays.

Oracle

Par souci de simplicité, cet échantillon ne vérifie que le nombre d’éléments, mais il peut être modifié pour afficher le contenu de chaque collection.

 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();
Copy
DBMS OUTPUT
-----------
0
0
3
2
0
3
1

Copy
Snowflake

Snowflake ne prend pas en charge les suppressions à partir d’un ARRAY existant et pour cette raison, la seule solution proposée est de reconstruire un nouveau ARRAY en fonction des paramètres d’origine de DELETE.

Note

Notez qu’une UDF a été ajoutée pour mettre en œuvre la fonctionnalité de mise à jour de l’élément.

Cette UDF sera ajoutée dans les révisions ultérieures.

 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;
Copy
DBMS OUTPUT
-----------
0
0
3
2
0
3
1

Copy

EXTEND

Cette méthode est utilisée pour ajouter de nouveaux éléments à une table imbriquée ou à un Varray. Il existe trois variantes possibles :

  • .EXTEND insère un élément null.

  • .EXTEND(n) insère « n » éléments nulls.

  • .EXTEND(n, i) insère « n » copies de l’élément situé à « 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();
Copy
DBMS OUTPUT
-----------
5
5
5

Copy
Snowflake

Note

Notez qu’une UDF a été ajoutée pour mettre en œuvre la fonctionnalité de mise à jour de l’élément.

Cette UDF sera ajoutée dans les révisions ultérieures.

 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;
Copy
DBMS OUTPUT
-----------
5
5
5

Copy

TRIM

Cette méthode est utilisée pour supprimer les derniers éléments d’une table imbriquée ou d’un Varray. Il existe deux variantes possibles :

  • .TRIM supprime le dernier élément.

  • .TRIM(n) supprime les « n » derniers éléments.

Note

Cette fonctionnalité peut être mise en œuvre à l’aide de 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();
Copy
DBMS OUTPUT
-----------
2
2

Copy

LIMIT

Cette méthode renvoie la limite maximale d’un Varray.

Cette méthode n’est pas prise en charge par 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();
Copy
DBMS OUTPUT
-----------
5
6

Copy

PRIOR/NEXT

Cette méthode renvoie l’index précédent/suivant, compte tenu d’un index. S’il n’y a pas d’antécédent/suivant, il renvoie null. Il est le plus souvent utilisé pour parcourir une collection.

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();
Copy
DBMS OUTPUT
-----------
        -- Empty spaces are due to null results
1
3


abc
jkl

jkl



Copy

Known Issues

1. Limit method is not supported in Snowflake

Snowflake ne prend pas en charge les varrays à espace limité. C’est pourquoi cette méthode n’est pas prise en charge.

Related EWIs

Pas d’EWIs connexes.

Définition du type de tableau de tables imbriquées

Avertissement

Les informations de cette section, en cours de modification, sont sujettes à modification.

Note

Cette section concerne la version PL/SQL des tableaux de tables imbriquées. Pour la version autonome, veuillez consulter Définition du type Table imbriquée.

Note

Certaines parties du code de sortie sont omises pour des raisons de clarté.

Description

Dans la base de données, une table imbriquée est un type de colonne qui stocke un nombre indéterminé de lignes sans ordre particulier.

Lorsque vous récupérez une valeur de table imbriquée de la base de données dans une variable de table imbriquée PL/SQL, PL/SQL donne aux lignes des index consécutifs, en commençant par 1. Grâce à ces index, vous pouvez accéder aux différentes lignes de la variable de la table imbriquée. La syntaxe est la suivante : variable_name(index). Les index et l’ordre des lignes d’une table imbriquée peuvent ne pas rester stables lorsque vous stockez et récupérez la table imbriquée dans la base de données.

(Référence linguistique Oracle PL/SQL NESTED TABLES)

Pour la traduction, la définition du type est remplacée par un ARRAY type de données semi-structurées et son utilisation est modifiée en conséquence pour toutes les opérations. Veuillez noter que la traduction pour les tables imbriquées et les varrays est la même.

Pour définir un type de tableau de tables imbriquées, la syntaxe est la suivante :

type_definition := TYPE IS TABLE OF datatype;

Copy

Pour déclarer une variable de ce type :

variable_name collection_type;

Copy

Modèles d’échantillons de sources

Définitions des tableaux de tables imbriquées

Ceci illustre comment créer différents tableaux de tables imbriquées et comment migrer les définitions des variables.

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;
Copy
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;
$$;
Copy

Itération des tables imbriquées

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();
Copy
DBMS OUTPUT
-----------
10
20
30
40
20
30

Copy
Snowflake

Note

Notez qu’une UDF a été ajoutée pour mettre en œuvre la fonctionnalité de mise à jour de l’élément.

Cette UDF sera ajoutée dans les révisions ultérieures.

 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;
Copy
 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)))
$$;
Copy
DBMS OUTPUT
-----------
10
20
30
40
20
30

Copy

Problèmes connus

1. They are currently not being converted

SnowConvert ne prend pas en charge la traduction de ces éléments.

2. Indexing needs to be modified

Les index d’Oracle commencent à 1, sur Snowflake ils commenceront à 0.

EWIs connexes

Pas d’EWIs connexes.

Définition du type d’enregistrement

Avertissement

Les informations de cette section, en cours de modification, sont sujettes à modification.

Note

Certaines parties du code de sortie sont omises pour des raisons de clarté.

Description

Une variable d’enregistrement est une variable composite dont les composants internes, appelés champs, peuvent avoir différents types de données. La valeur d’une variable d’enregistrement et les valeurs de ses champs peuvent changer.

Vous faites référence à une variable d’enregistrement entière par son nom. Vous faites référence à un champ de l’enregistrement avec la syntaxe suivante : record.field.

Vous pouvez créer une variable d’enregistrement de l’une ou l’autre de ces manières :

  • Définissez un type d’enregistrement, puis déclarez une variable de ce type.

  • Utilisez %ROWTYPE pour déclarer une variable d’enregistrement qui représente une ligne complète ou partielle d’une table de base de données ou d’une vue.

  • Utilisez %TYPE pour déclarer une variable d’enregistrement du même type qu’une variable d’enregistrement déclarée précédemment.

(Référence linguistique Oracle PL/SQL RECORD VARIABLES)

Pour la traduction, la définition du type est remplacée par un OBJECT Type de données semi-structurées et son utilisation est modifiée en conséquence pour toutes les opérations.

Pour définir un type d’enregistrement, la syntaxe est la suivante :

type_definition := TYPE IS RECORD ( field_definition [, field_definition...] );

field_definition := field_name datatype [ { [NOT NULL default ] | default } ]

default := [ { := | DEFAULT } expression]

Copy

Pour déclarer une variable de ce type :

variable_name { record_type
              | rowtype_attribute
              | record_variable%TYPE
              };

Copy

Modèles d’échantillons de sources

Note

Certaines parties du code de sortie sont omises pour des raisons de clarté.

Initialisation et affectation des enregistrements

Cet échantillon tente d’insérer deux nouvelles lignes à l’aide d’une variable d’enregistrement qui est réaffectée à mi-procédure.

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;
Copy
|COL1|COL2|
|----+----|
| 1.5|   1|
| 2.5|   2|

Copy
Snowflake

Remarquez que les réaffectations sont remplacées par une clause OBJECT_INSERT qui se met à jour si la colonne existe déjà, et que la clause VALUES est remplacée par une clause 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;
Copy
COL1|COL2|
----+----+
 1.5|   1|
 2.5|   2|

Copy

Enregistrement %ROWTYPE et enregistrement des valeurs

Comme ce sont les opérations qui définissent la structure, ces définitions peuvent être remplacées par un type de données OBJECT, mais les valeurs de l’enregistrement doivent être décomposées, car l’insertion de l’enregistrement « tel quel » n’est pas prise en charge.

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;
Copy
|COL1|   COL2|     COL3|
|----+-------|---------|
|   1|"Hello"|25-DEC-20|

Copy
Snowflake

Notez enfin que la variable OBJECT doit être initialisée pour que les informations puissent y être ajoutées.

 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;
Copy
|COL1|   COL2|     COL3|
|----+-------|---------|
|   1|"Hello"|25-DEC-20|

Copy

Récupération des données dans un enregistrement

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();
Copy
DBMS OUTPUT
-----------
1
Hello
25-DEC-20

Copy
Snowflake

Veuillez noter l’ajout de OBJECT_CONSTRUCT dans la définition du curseur, qui permet d’extraire une instruction OBJECT, qui peut ensuite être utilisée pour migrer de manière transparente l’instruction 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();
Copy
DBMS OUTPUT
-----------
1
Hello
25-DEC-20

Copy

Attribution d’une variable d’enregistrement dans un SELECT INTO

Cette transformation consiste à profiter de la fonction OBJECT_CONTRUCT pour initialiser l’enregistrement en utilisant les colonnes SELECT comme arguments.

Échantillon de code auxiliaire

 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');
Copy
 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');
Copy
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;
Copy
|COL1    |COL2  |
|--------|------|
|SELECT 1|NAME 1|
|SELECT 2|NAME 2|
|SELECT 3|NAME 3|
|SELECT 4|NAME 4|


Copy
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;
Copy
|COL1    |COL2  |
|--------|------|
|SELECT 1|NAME 1|
|SELECT 2|NAME 2|
|SELECT 3|NAME 3|
|SELECT 4|NAME 4|


Copy

Problèmes connus

1. The following functionalities are currently not being converted:

  • Récupération de données dans un enregistrement.

  • Enregistrements imbriqués (enregistrements à l’intérieur d’enregistrements).

  • Collections à l’intérieur des enregistrements.

EWIs connexes

  1. SSC-EWI-0036 : Type de données converti en un autre type de données.

  2. SSC-EWI-0056 : Type de création non pris en charge

  3. SSC-FDM-0006 : La colonne de type nombre peut ne pas se comporter de la même manière dans Snowflake.

  4. SSC-FDM-OR0042 : Le type de date transformé en horodatage a un comportement différent.

  5. SSC-FDM-OR0035 : DBMS_OUTPUT.PUTLINE vérifie la mise en œuvre de l’UDF.

  6. SSC-PRF-0003 : Fetch à l’intérieur d’une boucle est considéré comme un modèle complexe, ce qui pourrait dégrader les performances de Snowflake.

Définition du type varray

Avertissement

Les informations de cette section, en cours de modification, sont sujettes à modification.

Note

Cette section concerne la version PL/SQL des Varrays. Pour la version autonome, veuillez consulter Définition du type tableau.

Note

Certaines parties du code de sortie sont omises pour des raisons de clarté.

Description

Un varray (tableau à taille variable) est un tableau dont le nombre d’éléments peut varier de zéro (vide) à la taille maximale déclarée.

Pour accéder à un élément d’une variable varray, utilisez la syntaxe suivante : variable_name(index). La borne inférieure de l”index est 1 ; la borne supérieure est le nombre actuel d’éléments. La borne supérieure change à mesure que vous ajoutez ou supprimez des éléments, mais elle ne peut pas dépasser la taille maximale. Lorsque vous stockez et récupérez un varray dans la base de données, ses index et l’ordre des éléments restent stables.

(Référence linguistique Oracle PL/SQL VARRAYS)

Pour la traduction, la définition du type est remplacée par un ARRAY type de données semi-structurées et son utilisation est modifiée en conséquence pour toutes les opérations. Veuillez noter que la traduction pour les tables imbriquées et les varrays est la même.

Pour définir un type de tableau, la syntaxe est la suivante :

type_definition := { VARRAY | [VARYING] ARRAY } (size_limit) OF datatype
            [NOT NULL];

Copy

Pour déclarer une variable de ce type :

variable_name collection_type;

Copy

Modèles d’échantillons de sources

Définitions de varray

Ceci illustre les trois différentes façons de créer un varray, et la manière de migrer ces définitions pour les variables.

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;
Copy
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;
$$;
Copy

Itération 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();
Copy
DBMS OUTPUT
-----------
10
20
30
40
20
30

Copy
Snowflake

Note

Notez qu’une UDF a été ajoutée pour mettre en œuvre la fonctionnalité de mise à jour de l’élément.

Cette UDF sera ajoutée dans les révisions ultérieures.

 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();
Copy
 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)))
$$;
Copy
DBMS OUTPUT
-----------
10
20
30
40
20
30

Copy

Problèmes connus

1. They are currently not being converted

SnowConvert ne prend pas en charge la traduction de ces éléments.

2. Indexing needs to be modified

Les index d’Oracle commencent à 1, sur Snowflake ils commenceront à 0.

3. Array Density may not match the original

Le type de données ARRAY pouvant devenir clairsemé, il convient d’être prudent lors de l’ajout ou de la suppression du tableau. L’utilisation de ARRAY_COMPACT() après de telles opérations peut être utile si la densité est un sujet de préoccupation.

EWIs connexes

  1. SSC-EWI-0058 : La fonctionnalité n’est pas prise en charge actuellement par Snowflake Scripting.

  2. SSC-EWI-0062 : L’utilisation du type personnalisé a été modifiée en variante.

  3. SSC-EWI-0073 : En attente de l’examen de l’équivalence fonctionnelle.

  4. SSC-EWI-OR0108 : L’instruction d’affectation suivante n’est pas prise en charge par Snowflake Scripting.

  5. SSC-FDM-OR0035 : DBMS_OUTPUT.PUTLINE vérifie la mise en œuvre de l’UDF.

Opérations de collection en masse

Avertissement

Les informations de cette section, en cours de modification, sont sujettes à modification.

Note

Certaines parties du code de sortie sont omises pour des raisons de clarté.

Description

La clause BULK COLLECT, une fonction de SQL en masse, renvoie les résultats de SQL à PL/SQL par lots plutôt qu’un par un.

La clause BULK COLLECT peut figurer dans :

  • Instruction SELECT INTO

  • Instruction FETCH

  • Clause de RETURNING INTO :

    • Instruction DELETE

    • Instruction INSERT

    • Instruction UPDATE

    • Instruction EXECUTE IMMEDIATE

Avec la clause BULK COLLECT, chacune des instructions précédentes récupère un jeu de résultats complet et le stocke dans une ou plusieurs variables de collection en une seule opération (ce qui est plus efficace que d’utiliser une instruction de boucle pour récupérer une ligne de résultats à la fois).

(Référence linguistique Oracle PL/SQL BULK COLLECT CLAUSE)

Cette section propose des solutions de contournement pour les SELECTs et le curseur FETCH avec clauses Bulk.

Modèles d’échantillons de sources

Table source

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);
Copy
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);
Copy

Bulk Collect à partir d’une table

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();
Copy
DBMS OUTPUT
-----------
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

Copy
Snowflake

EXECUTE IMMEDIATE avec la clause Bulk Collect n’a pas de solution de contournement proposée.

Note

Veuillez noter que, bien que le curseur FETCH puisse être conservé dans une large mesure, il est conseillé de le remplacer par des instructions SELECT dans la mesure du possible pour des raisons de performance.

 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();
Copy
DBMS OUTPUT
-----------
1
2
3
4
5
6
7
8
9
10
11
    -- EXECUTE IMMEDIATE NOT EXECUTED, it's not supported

Copy

Cas d’instruction SELECT INTO

Dans ce cas, la spécification de traduction utilise des RESULTSETs. Consultez la documentation relative aux instructions WITH, SELECT et BULK COLLECT INTO ici :

with-select-and-bulk-collect-into-statements.md

Problèmes connus

1. Heavy performance issues on FETCH Cursor workaround

La solution de contournement pour le curseur Fetch a des exigences élevées en matière de performance en raison de la table temporaire. Il est conseillé de les migrer manuellement vers les instructions SELECT

2. Execute immediate statements are not transformed

Elles ne sont pas prises en charge par SnowConvert mais peuvent être modifiées manuellement en instructions SELECT.

EWIs connexes

  1. SSC-EWI-0058 : La fonctionnalité n’est pas prise en charge actuellement par Snowflake Scripting.

  2. SSC-EWI-0062 : L’utilisation du type personnalisé a été modifiée en variante.

  3. SSC-EWI-0073 : En attente de l’examen de l’équivalence fonctionnelle

  4. SSC-EWI-OR0036 : Problèmes de résolution de types, l’opération arithmétique peut ne pas se comporter correctement entre une chaîne et une date.

  5. SSC-EWI-OR0108 : L’instruction d’affectation suivante n’est pas prise en charge par Snowflake Scripting.

  6. SSC-FDM-OR0035 : DBMS_OUTPUT.PUTLINE vérifie la mise en œuvre de l’UDF.

  7. SSC-PRF-0001 : Cette instruction a des utilisations d’opérations de curseur fetch bulk.

  8. SSC-EWI-0030 : L’instruction ci-dessous a des utilisations de SQL dynamique

Instructions WITH, SELECT et BULKCOLLECTINTO

Cette section est une spécification de traduction. Les informations sont susceptibles d’être modifiées à l’avenir.

Note

Certaines parties du code de sortie sont omises pour des raisons de clarté.

Description

Cette section est une spécification de traduction de l’instruction WITH faisant suite à une instruction SELECT qui utilise une instruction BULK COLLECT INTO. Pour plus d’informations, consultez la documentation suivante :

Modèles d’échantillons de sources

Note

Certaines parties du code de sortie sont omises pour des raisons de clarté.

La requête suivante est utilisée pour les exemples suivants.

 -- 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');
Copy
 -- 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');
Copy

1. Inside procedure simple case

Il s’agit d’une approche qui utilise un type de données resultset. Les types définis par l’utilisateur doivent être revus. Consultez la documentation suivante de Snowflake pour obtenir plus d’informations sur RESULTSETs.

L’exemple suivant utilise un type défini par l’utilisateur et le déclare indirectement comme une table. La traduction pour ce cas met en œuvre un RESULTSET comme type de données dans Snowflake. Le jeu de résultats est stocké dans une variable qui doit être renvoyée enveloppée dans une fonction 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();
Copy

Note

La requête ne renvoie pas de résultats, mais l’information recueillie attendue serait l’information salariale IT utilisée pour l’exemple :

IT_Salary

75000

80000

L’une des limites des RESULTSETs est qu’ils ne peuvent pas être utilisés comme des tables. Par exemple : select * from my_result_set; (Il s’agit d’une erreur, consultez la documentation suivante pour plus d’informations).

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();
Copy

SALARY

77500

80000

2. Simple case for iterations: FOR LOOP statement

Le cas suivant consiste à définir une traduction pour l’itération avec FOR...LOOP. Dans ce cas, le type défini par l’utilisateur est implicitement une table, il est donc possible d’utiliser un curseur pour itérer. Consultez la documentation suivante pour en savoir plus :

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();
Copy
Statement processed.
Average Salary for IT Department: 77500

Copy
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();
Copy

SIMPLE_PROCEDURE

Salaire moyen pour le département IT : 77500

Known Issues

1. Resulset limitations.

L’utilisation du type de données RESULTSET comporte des limites. Consultez la documentation Snowflake pour en savoir plus. Les limites à ne pas dépasser sont les suivantes :

  • Déclarer une colonne de type RESULTSET.

  • Déclarer un paramètre de type RESULTSET.

  • Déclaration du type de retour d’une procédure stockée en tant que RESULTSET.

2. Execute statements with Bulk Collect clause are not supported.

Consultez la documentation suivante.

Related EWIs

  1. SSC-EWI-0058 : La fonctionnalité n’est pas prise en charge actuellement par Snowflake Scripting.

  2. SSC-EWI-0062 : L’utilisation du type personnalisé a été modifiée en variante.

  3. SSC-EWI-0073 : En attente de l’examen de l’équivalence fonctionnelle

  4. SSC-EWI-OR0036 : Problèmes de résolution de types, l’opération arithmétique peut ne pas se comporter correctement entre une chaîne et une date.

  5. SSC-EWI-OR0072 : Membre de procédure non pris en charge

  6. SSC-EWI-OR0104 : Variable de collection inutilisable.

  7. SSC-FDM-0006 : La colonne de type nombre peut ne pas se comporter de la même manière dans Snowflake.

  8. SSC-FDM-OR0035 : DBMS_OUTPUT.PUTLINE vérifie la mise en œuvre de l’UDF.

HELPERS

Assistants du curseur Bulk

Note

Vous pourriez également être intéressé par Transformation FORALL par défaut.

Le curseur est simulé à l’aide d’un OBJECT contenant différentes informations sur l’état du curseur. Une table temporaire est créée pour stocker le jeu de résultats de la requête du curseur.

La plupart de ces procédures renvoient un nouvel objet contenant l’état actualisé du curseur.

INIT_CURSOR

Cette fonction initialise un nouvel objet avec les informations de base sur le curseur

 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)
$$;
Copy

OPEN_BULK_CURSOR

Ces procédures créent une table temporaire avec la requête du curseur. Une surcharge optionnelle existe pour prendre en charge les liaisons.

 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;
$$;
Copy
 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;
$$;
Copy

CLOSE_BULK_CURSOR

Cette procédure supprime la table temporaire qui stockait le jeu de résultats du curseur et remet les paramètres du curseur à leur état initial.

 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;
$$;
Copy

Assistants FETCH

Oracle étant capable d’exécuter l’instruction FETCH pour différents types de scénarios, plusieurs procédures avec des surcharges ont été créées pour traiter chaque cas. Ces assistants enregistrent les valeurs obtenues dans la propriété RESULT de l’objet CURSOR.

Certaines des surcharges comprennent des variations lorsque la clause LIMIT a été utilisée ou non. D’autres surcharges ont un argument COLUMN_NAMES qui est nécessaire lorsque l’instruction FETCH est effectuée dans une variable qui a ou contient des enregistrements dont les noms de colonnes sont différents des noms de colonnes de la requête.

FETCH_BULK_COLLECTION_RECORDS

Ces procédures sont utilisées lorsqu’un FETCH BULK est créé dans une collection d’enregistrements.

 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;
$$;
Copy
 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;
$$;
Copy
 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;
$$;
Copy
 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;
$$;
Copy

FETCH_BULK_COLLECTIONS

Ces procédures sont utilisées lorsque l’instruction FETCH est effectuée dans une ou plusieurs collections. Comme les colonnes sont spécifiées dans cette opération FETCH, il n’est pas nécessaire de prévoir une dérogation pour une COLUMN_NAMES spécifique.

 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;
$$;
Copy
 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;
$$;
Copy

FETCH_BULK_RECORD_COLLECTIONS

Ces procédures sont utilisées lorsqu’un FETCH BULK est effectué dans un enregistrement de collections.

 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;
$$;
Copy
 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;
$$;
Copy
 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;
$$;
Copy
 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;
$$;
Copy