SnowConvert AI - Oracle - COLLECTIONS AND RECORDS¶
Référence de traduction pour convertir COLLECTIONS et RECORDS Oracle vers Snowflake Scripting
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
Veuillez tenir compte de la référence de traduction d’instruction CREATE TYPE, car certaines solutions de contournement peuvent se chevaucher et peuvent ê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 SnowConvert AI actuelle¶
Le tableau suivant présente un résumé de la prise en charge actuelle par l’outil SnowConvert AI. Veuillez tenir compte du fait que les traductions peuvent ne pas être finales et que des tâches supplémentaire peuvent être nécessaire.
Sous-fonctionnalité |
Statut actuel de reconnaissance |
Statut actuel de la traduction |
Solutions de contournement connues |
|---|---|---|---|
Reconnu. |
Non traduit. |
Oui. |
|
Non reconnu. |
Non traduit. |
Oui. |
|
Reconnu. |
Non traduit. |
Oui. |
|
Reconnu. |
Non traduit. |
Oui. |
Problèmes connus¶
1. Associate Arrays are considered a Nested Table¶
Actuellement, SnowConvert AI 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 comptages d’évaluation.
Définition du type de tableau associatif¶
Il s’agit d’une référence de traduction pour convertir la déclaration Array (tableau) associatif Oracle vers Snowflake.
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”
indexpeut être un type de chaîne (VARCHAR2,VARCHAR,STRINGouLONG) ouPLS_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’initialisationNLS_SORTetNLS_COMP.
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
}
Pour déclarer une variable de ce type :
variable_name collection_type;
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();
Résultat¶
DBMS OUTPUT |
|---|
1 |
3 |
4 |
2 |
3 |
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;
Résultat¶
DBMS OUTPUT |
|---|
1 |
3 |
4 |
2 |
3 |
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();
Résultat¶
DBMS OUTPUT |
|---|
-1 |
3 |
-4 |
-2 |
-3 |
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;
Résultat¶
DBMS OUTPUT |
|---|
-1 |
3 |
-4 |
-2 |
-3 |
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();
Résultat¶
DBMS OUTPUT |
|---|
-1 |
3 |
-4 |
-2 |
-3 |
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;
Résultat¶
DBMS OUTPUT |
|---|
-1 |
3 |
-4 |
-2 |
-3 |
Problèmes connus¶
1. They are currently not being recognized¶
SnowConvert AI traite ces collections comme des tableaux de tables imbriquées. Il existe une solution pour y remédier.
EWIs connexes¶
Pas d’EWIs connexes.
Méthodes de collection¶
Il s’agit d’une référence de traduction pour convertir les méthodes de collection Oracle vers Snowflake.
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.
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 SnowConvert AI actuelle¶
Le tableau suivant présente un résumé de la prise en charge actuelle par l’outil SnowConvert AI. Veuillez tenir compte du fait que les traductions peuvent ne pas être finales et que des tâches supplémentaire peuvent être nécessaire.
Méthode |
Statut actuel de reconnaissance |
Statut actuel de la traduction |
Mappé vers |
|---|---|---|---|
Non reconnu. |
Non traduit. |
UDF |
|
Non reconnu. |
Non traduit. |
UDF (à définir) |
|
Non reconnu. |
Non traduit. |
UDF |
|
Non reconnu. |
Non traduit. |
||
Non reconnu. |
Non traduit. |
UDF |
|
Non reconnu. |
Non traduit. |
UDF |
|
Non reconnu. |
Non traduit. |
||
Non reconnu. |
Non traduit. |
Non pris en charge. |
|
Non reconnu. |
Non traduit. |
UDF (à définir) |
|
Non reconnu. |
Non traduit. |
UDF (à définir) |
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();
Résultat¶
DBMS OUTPUT |
|---|
2 |
3 |
4 |
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;
Résultat¶
DBMS OUTPUT |
|---|
2 |
3 |
4 |
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();
Résultat¶
DBMS OUTPUT |
|---|
2 |
3 |
4 |
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;
Résultat¶
DBMS OUTPUT |
|---|
2 |
3 |
4 |
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();
Résultat¶
DBMS OUTPUT |
|---|
abc |
bca |
–Ces espaces vides sont dus au fait qu’ils correspondent à null |
1 |
4 |
Snowflake¶
CREATE OR REPLACE PROCEDURE PUBLIC.collection_first_last()
RETURNS VARCHAR
LANGUAGE SQL
EXECUTE AS CALLER
AS
$$
DECLARE
associative_array OBJECT := OBJECT_CONSTRUCT('abc', 1, 'bca', 1);
nt_variable ARRAY := ARRAY_CONSTRUCT();
BEGIN
CALL DBMS_OUTPUT.PUT_LINE(ARRAY_FIRST(:associative_array));
CALL DBMS_OUTPUT.PUT_LINE(ARRAY_LAST(:associative_array));
CALL DBMS_OUTPUT.PUT_LINE(ARRAY_FIRST(:nt_variable));
CALL DBMS_OUTPUT.PUT_LINE(ARRAY_LAST(:nt_variable));
nt_variable := ARRAY_CONSTRUCT(1, 2, 3, 4);
CALL DBMS_OUTPUT.PUT_LINE(ARRAY_FIRST(:nt_variable));
CALL DBMS_OUTPUT.PUT_LINE(ARRAY_LAST(:nt_variable));
END;
$$;
CALL PUBLIC.collection_first_last();
SELECT * FROM DBMS_OUTPUT.DBMS_OUTPUT_LOG;
UDFs¶
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]))
$$;
Résultat¶
DBMS OUTPUT |
|---|
abc |
bca |
–Ces espaces vides sont dus au fait qu’ils correspondent à null |
1 |
4 |
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();
Résultat¶
DBMS OUTPUT |
|---|
0 |
0 |
3 |
2 |
0 |
3 |
1 |
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;
Résultat¶
DBMS OUTPUT |
|---|
0 |
0 |
3 |
2 |
0 |
3 |
1 |
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();
Résultat¶
DBMS OUTPUT |
|---|
5 |
5 |
5 |
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;
Résultat¶
DBMS OUTPUT |
|---|
5 |
5 |
5 |
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();
Résultat¶
DBMS OUTPUT
-----------
2
2
LIMIT¶
Cette méthode renvoie la limite maximale d’un Varray.
Danger
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();
Résultat¶
DBMS OUTPUT |
|---|
5 |
6 |
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();
Résultat¶
DBMS OUTPUT |
|---|
– Les espaces vides sont dus aux résultats nuls |
1 |
3 |
abc |
jkl |
jkl |
Problèmes connus¶
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.
EWIs connexes¶
Pas d’EWIs connexes.
Définition du type de tableau de tables imbriquées¶
Il s’agit d’une référence de traduction pour convertir la déclaration de tableau de tables imbriquées d’Oracle vers Snowflake
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, voir Définition du type de 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.
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;
Pour déclarer une variable de ce type :
variable_name collection_type;
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;
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;
$$;
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();
Résultat¶
DBMS OUTPUT |
|---|
10 |
20 |
30 |
40 |
20 |
30 |
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;
UDF¶
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)))
$$;
Résultat¶
DBMS OUTPUT |
|---|
10 |
20 |
30 |
40 |
20 |
30 |
Problèmes connus¶
1. They are currently not being converted¶
SnowConvert AI 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¶
Il s’agit d’une référence de traduction pour convertir la déclaration de l’enregistrement Oracle vers Snowflake
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
%ROWTYPEpour 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
%TYPEpour déclarer une variable d’enregistrement du même type qu’une variable d’enregistrement déclarée précédemment.
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]
Pour déclarer une variable de ce type :
variable_name { record_type
| rowtype_attribute
| record_variable%TYPE
};
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;
Résultat¶
COL1 |
COL2 |
|---|---|
1,5 |
1 |
2.5 |
2 |
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;
Résultat¶
COL1 |
COL2 |
|---|---|
1,5 |
1 |
2.5 |
2 |
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;
Résultat¶
COL1 |
COL2 |
COL3 |
|---|---|---|
1 |
« Hello » |
25-DEC-20 |
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;
Résultat¶
COL1 |
COL2 |
COL3 |
|---|---|---|
1 |
« Hello » |
25-DEC-20 |
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();
Résultat¶
DBMS OUTPUT |
|---|
1 |
Bonjour |
25-DEC-20 |
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
--** SSC-PRF-0009 - PERFORMANCE REVIEW - CURSOR USAGE **
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;
--** SSC-PRF-0008 - PERFORMANCE REVIEW - LOOP USAGE **
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();
Résultat¶
DBMS OUTPUT |
|---|
1 |
Bonjour |
25-DEC-20 |
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¶
Oracle¶
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');
Snowflake¶
CREATE OR REPLACE TABLE sample_table (ID NUMBER(38, 18) /*** SSC-FDM-0006 - NUMBER TYPE COLUMN MAY NOT BEHAVE SIMILARLY IN SNOWFLAKE. ***/,
NAME VARCHAR(23))
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"oracle"}}'
;
CREATE OR REPLACE TABLE RESULTS (COL1 VARCHAR(20),
COL2 VARCHAR(40))
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"oracle"}}'
;
insert into sample_table
values(1, 'NAME 1');
insert into sample_table
values(2, 'NAME 2');
insert into sample_table
values(3, 'NAME 3');
insert into sample_table
values(4, 'NAME 4');
Oracle¶
CREATE OR REPLACE PROCEDURE sp_sample1 AS
-- Rowtype variable
rowtype_variable sample_table%rowtype;
--Record variable
TYPE record_typ_def IS RECORD(ID number, NAME varchar2(23));
record_variable_def record_typ_def;
-- Auxiliary variable
name_var VARCHAR(20);
BEGIN
SELECT * INTO rowtype_variable FROM sample_table WHERE ID = 1 FETCH NEXT 1 ROWS ONLY;
name_var := rowtype_variable.NAME;
INSERT INTO RESULTS(COL1, COL2) VALUES('SELECT 1', name_var);
SELECT ID, NAME INTO rowtype_variable FROM sample_table WHERE ID = 2 FETCH NEXT 1 ROWS ONLY;
name_var := rowtype_variable.NAME;
INSERT INTO RESULTS(COL1, COL2) VALUES('SELECT 2', name_var);
SELECT * INTO record_variable_def FROM sample_table WHERE ID = 3 FETCH NEXT 1 ROWS ONLY;
name_var := record_variable_def.NAME;
INSERT INTO RESULTS(COL1, COL2) VALUES('SELECT 3', name_var);
SELECT ID, NAME INTO record_variable_def FROM sample_table WHERE ID = 4 FETCH NEXT 1 ROWS ONLY;
name_var := record_variable_def.NAME;
INSERT INTO RESULTS(COL1, COL2) VALUES('SELECT 4', name_var);
END;
call sp_sample1();
SELECT * FROM results;
Résultat¶
COL1 |
COL2 |
|---|---|
SELECT 1 |
NAME 1 |
SELECT 2 |
NAME 2 |
SELECT 3 |
NAME 3 |
SELECT 4 |
NAME 4 |
Snowflake¶
CREATE OR REPLACE PROCEDURE sp_sample1 ()
RETURNS VARCHAR
LANGUAGE SQL
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"oracle"}}'
EXECUTE AS CALLER
AS
$$
DECLARE
-- Rowtype variable
rowtype_variable OBJECT !!!RESOLVE EWI!!! /*** SSC-EWI-0036 - ROWTYPE DATA TYPE CONVERTED TO OBJECT ***/!!! := OBJECT_CONSTRUCT();
--Record variable
!!!RESOLVE EWI!!! /*** SSC-EWI-0056 - CUSTOM TYPES ARE NOT SUPPORTED IN SNOWFLAKE BUT REFERENCES TO THIS CUSTOM TYPE WERE CHANGED TO OBJECT ***/!!!
TYPE record_typ_def IS RECORD(ID number, NAME varchar2(23));
record_variable_def OBJECT !!!RESOLVE EWI!!! /*** SSC-EWI-0036 - record_typ_def DATA TYPE CONVERTED TO OBJECT ***/!!! := OBJECT_CONSTRUCT();
-- Auxiliary variable
name_var VARCHAR(20);
BEGIN
SELECT
OBJECT_CONSTRUCT( *) INTO
:rowtype_variable
FROM
sample_table
WHERE ID = 1
FETCH NEXT 1 ROWS ONLY;
name_var := :rowtype_variable:NAME;
INSERT INTO RESULTS(COL1, COL2) VALUES('SELECT 1', :name_var);
SELECT
OBJECT_CONSTRUCT()
INTO
:rowtype_variable
FROM
sample_table
WHERE ID = 2
FETCH NEXT 1 ROWS ONLY;
name_var := :rowtype_variable:NAME;
INSERT INTO RESULTS(COL1, COL2) VALUES('SELECT 2', :name_var);
SELECT
OBJECT_CONSTRUCT( *) INTO
:record_variable_def
FROM
sample_table
WHERE ID = 3
FETCH NEXT 1 ROWS ONLY;
name_var := :record_variable_def:NAME;
INSERT INTO RESULTS(COL1, COL2) VALUES('SELECT 3', :name_var);
SELECT
OBJECT_CONSTRUCT('ID', ID, 'NAME', NAME) INTO
:record_variable_def
FROM
sample_table
WHERE ID = 4
FETCH NEXT 1 ROWS ONLY;
name_var := :record_variable_def:NAME;
INSERT INTO RESULTS(COL1, COL2) VALUES('SELECT 4', :name_var);
END;
$$;
call sp_sample1();
SELECT * FROM
results;
Résultat¶
COL1 |
COL2 |
|---|---|
SELECT 1 |
NAME 1 |
SELECT 2 |
NAME 2 |
SELECT 3 |
NAME 3 |
SELECT 4 |
NAME 4 |
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¶
SSC-EWI-0036 : Type de données converti en un autre type de données.
SSC-EWI-0056: Le type de création ’Create Type’ n’est pas pris en charge
SSC-FDM-0006: La colonne de type nombre peut ne pas se comporter de la même manière dans Snowflake.
SSC-FDM-OR0042: Le type de date transformé en horodatage a un comportement différent.
SSC-FDM-OR0035: DBMS_OUTPUT.PUTLINE consultez l’implémentation UDF.
SSC-PRF-0003: Fetch à l’intérieur d’une boucle est considéré comme un modèle complexe, cela pourrait dégrader les performances de Snowflake.
Définition du type varray¶
Il s’agit d’une référence de traduction pour convertir la déclaration Oracle Varray vers Snowflake
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, voir Définition de type Array (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”indexest 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.
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];
Pour déclarer une variable de ce type :
variable_name collection_type;
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;
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;
$$;
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();
Résultat¶
DBMS OUTPUT |
|---|
10 |
20 |
30 |
40 |
20 |
30 |
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
--** SSC-PRF-0008 - PERFORMANCE REVIEW - LOOP USAGE **
FOR i IN 1 TO 0 /*varray_variable.COUNT*/!!!RESOLVE EWI!!! /*** SSC-EWI-0073 - PENDING FUNCTIONAL EQUIVALENCE REVIEW FOR 'VARRAY CUSTOM TYPE EXPRESSION' NODE ***/!!!
--** SSC-PRF-0008 - PERFORMANCE REVIEW - LOOP USAGE **
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;
--** SSC-PRF-0008 - PERFORMANCE REVIEW - LOOP USAGE **
FOR i IN 1 TO 0 /*varray_variable.COUNT*/!!!RESOLVE EWI!!! /*** SSC-EWI-0073 - PENDING FUNCTIONAL EQUIVALENCE REVIEW FOR 'VARRAY CUSTOM TYPE EXPRESSION' NODE ***/!!!
--** SSC-PRF-0008 - PERFORMANCE REVIEW - LOOP USAGE **
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();
UDF¶
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)))
$$;
Résultat¶
DBMS OUTPUT |
|---|
10 |
20 |
30 |
40 |
20 |
30 |
Problèmes connus¶
1. They are currently not being converted¶
SnowConvert AI 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¶
SSC-EWI-0058: La fonctionnalité n’est pas prise en charge actuellement par Snowflake Scripting.
SSC-EWI-0062: L’utilisation du type personnalisé a changé en variante.
SSC-EWI-0073 : En attente de l’examen de l’équivalence fonctionnelle.
SSC-EWI-OR0108: L’instruction d’affectation suivante n’est pas prise en charge par Snowflake Scripting.
SSC-FDM-OR0035: DBMS_OUTPUT.PUTLINE consultez l’implémentation UDF.
Opérations de collection en masse¶
Il s’agit d’une référence de traduction pour convertir les opérations de collection en masse Oracle vers Snowflake
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
BULKCOLLECT, une fonction de SQL en masse, renvoie les résultats de SQL à PL/SQL par lots plutôt qu’un par un.La clause
BULKCOLLECTpeut figurer dans :
Instruction
SELECTINTOInstruction
FETCHClause de
RETURNINGINTO:
Instruction
DELETEInstruction
INSERTInstruction
UPDATEInstruction
EXECUTEIMMEDIATEAvec la clause
BULKCOLLECT, 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);
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);
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();
Résultat¶
DBMS OUTPUT |
|---|
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
Snowflake¶
Danger
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
--** SSC-PRF-0009 - PERFORMANCE REVIEW - CURSOR USAGE **
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;
--** SSC-PRF-0008 - PERFORMANCE REVIEW - LOOP USAGE **
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 ***/!!!
--** SSC-PRF-0008 - PERFORMANCE REVIEW - LOOP USAGE **
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;
--** SSC-PRF-0008 - PERFORMANCE REVIEW - LOOP USAGE **
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 ***/!!!
--** SSC-PRF-0008 - PERFORMANCE REVIEW - LOOP USAGE **
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;
--** SSC-PRF-0008 - PERFORMANCE REVIEW - LOOP USAGE **
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 ***/!!!
--** SSC-PRF-0008 - PERFORMANCE REVIEW - LOOP USAGE **
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();
Résultat¶
DBMS OUTPUT |
|---|
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
– EXECUTE IMMEDIATE NOT EXECUTED n’est pas pris en charge |
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 :
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 AI mais peut être manuellement remplacé par des instructions SELECT.
EWIs connexes¶
SSC-EWI-0058: La fonctionnalité n’est pas prise en charge actuellement par Snowflake Scripting.
SSC-EWI-0062: L’utilisation du type personnalisé a changé en variante.
SSC-EWI-0073 : En attente de l’examen de l’équivalence fonctionnelle
SSC-EWI-OR0036: Problèmes de résolution des types, l’opération arithmétique peut ne pas se comporter correctement entre la chaîne et la date.
SSC-EWI-OR0108: L’instruction d’affectation suivante n’est pas prise en charge par Snowflake Scripting.
SSC-FDM-OR0035: DBMS_OUTPUT.PUTLINE consultez l’implémentation UDF.
SSC-PRF-0001: Cette instruction a des utilisations des opérations en masse de curseur Fetch.
SSC-EWI-0030: L’instruction ci-dessous a des utilisations de Dynamic SQL
Instructions WITH, SELECT et BULKCOLLECTINTO¶
Danger
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.
Oracle¶
-- 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');
Snowflake¶
-- Sample MySampleTable table
CREATE OR REPLACE TABLE MySampleTable (
MySampleID NUMBER(38, 18) /*** SSC-FDM-0006 - NUMBER TYPE COLUMN MAY NOT BEHAVE SIMILARLY IN SNOWFLAKE. ***/ PRIMARY KEY,
FirstName VARCHAR(50),
Salary NUMBER(38, 18) /*** SSC-FDM-0006 - NUMBER TYPE COLUMN MAY NOT BEHAVE SIMILARLY IN SNOWFLAKE. ***/,
Department VARCHAR(50)
)
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"oracle"}}'
;
-- Insert some sample data
INSERT INTO MySampleTable(MySampleID, FirstName, Salary, Department)
VALUES (1, 'Bob One', 50000, 'HR');
INSERT INTO MySampleTable(MySampleID, FirstName, Salary, Department)
VALUES (2, 'Bob Two', 60000, 'HR');
INSERT INTO MySampleTable(MySampleID, FirstName, Salary, Department)
VALUES (3, 'Bob Three', 75000, 'IT');
INSERT INTO MySampleTable(MySampleID, FirstName, Salary, Department)
VALUES (4, 'Bob Four', 80000, 'IT');
1. Inside procedure simple case¶
Danger
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¶
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();
Résultat¶
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 |
Danger
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¶
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 AI Helpers Code section is omitted.
!!!RESOLVE EWI!!! /*** SSC-EWI-OR0072 - PROCEDURAL MEMBER TYPE DEFINITION NOT SUPPORTED. ***/!!!
/* TYPE salary_collection IS TABLE OF NUMBER */
;
!!!RESOLVE EWI!!! /*** SSC-EWI-OR0104 - UNUSABLE VARIABLE, ITS TYPE WAS NOT TRANSFORMED ***/!!!
/* v_salaries salary_collection := salary_collection() */
;
EXEC(`SELECT Salary
FROM
MySampleTable
WHERE Department = 'IT'`);
[
!!!RESOLVE EWI!!! /*** SSC-EWI-0073 - PENDING FUNCTIONAL EQUIVALENCE REVIEW FOR 'PlBulkCollectionItem' NODE ***/!!!
//v_salaries
null,V_SALARIES] = EXEC(`SELECT
Salary
FROM IT_Employees`);
$$;
CALL simple_procedure();
Résultat¶
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 :
Documentation de Snowflake sur le renvoi d’une table pour un curseur
Dans ce cas, il est nécessaire de créer un curseur pour l’itération. Consultez la documentation suivante sur la syntaxe d’affectation du curseur.
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();
Résultat¶
Statement processed.
Average Salary for IT Department: 77500
Snowflake¶
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;
--** SSC-PRF-0008 - PERFORMANCE REVIEW - LOOP USAGE **
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 ***/!!!
--** SSC-PRF-0008 - PERFORMANCE REVIEW - LOOP USAGE **
LOOP
v_average_salary :=
!!!RESOLVE EWI!!! /*** SSC-EWI-OR0036 - TYPES RESOLUTION ISSUES, ARITHMETIC OPERATION '+' MAY NOT BEHAVE CORRECTLY BETWEEN NUMBER 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();
Résultat¶
SIMPLE_PROCEDURE |
|---|
Salaire moyen pour le département IT : 77500 |
Problèmes connus¶
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.
EWIs connexes¶
SSC-EWI-0058: La fonctionnalité n’est pas prise en charge actuellement par Snowflake Scripting.
SSC-EWI-0062: L’utilisation du type personnalisé a changé en variante.
SSC-EWI-0073 : En attente de l’examen de l’équivalence fonctionnelle
SSC-EWI-OR0036: Problèmes de résolution des types, l’opération arithmétique peut ne pas se comporter correctement entre la chaîne et la date.
SSC-EWI-OR0072: Membre procédural non pris en charge
SSC-EWI-OR0104: Variable de collection inutilisable.
SSC-FDM-0006: La colonne de type nombre peut ne pas se comporter de la même manière dans Snowflake.
SSC-FDM-OR0035: DBMS_OUTPUT.PUTLINE consultez l’implémentation UDF.