Instructions PL/pgSQL prises en charge - Amazon Redshift

Les traductions sont fournies par des outils de traduction automatique. En cas de conflit entre le contenu d'une traduction et celui de la version originale en anglais, la version anglaise prévaudra.

Instructions PL/pgSQL prises en charge

Les instructions PL/pgSQL complémentent les commandes SQL avec des constructions procédurales, y compris des expressions de boucle et conditionnelles, pour contrôler le flux logique. La plupart des commandes SQL peuvent être utilisées, y compris celles du langage de manipulation de données (DML) telles que COPY, UNLOAD et INSERT, et celles du langage de définition de données (DDL) telles que CREATE TABLE. Pour obtenir la liste complète des commandes SQL, veuillez consulter SQLcommandes. De plus, les instructions PL/pgSQL suivantes sont prises en charge par Amazon Redshift.

Affectation

L'instruction d'affectation affecte une valeur à une variable. L'expression doit renvoyer une valeur unique.

identifier := expression;

L'utilisation de l'élément non standard = pour l'affectation, à la place de :=, est également acceptée.

Si le type de données de l'expression ne correspond pas au type de données de la variable ou si la variable a une taille ou une précision, la valeur obtenue est implicitement convertie.

Des exemples sont fournis ci-dessous.

customer_number := 20; tip := subtotal * 0.15;

SELECT INTO

L'instruction SELECT INTO affecte le résultat de plusieurs colonnes (mais d'une seule ligne) dans une variable d'enregistrement ou une liste de variables scalaires.

SELECT INTO target select_expressions FROM ...;

Dans la syntaxe précédente, target peut être une variable d'enregistrement ou une liste séparée par des virgules de variables simples et de champs d'enregistrement. La liste select_expressions et le reste de la commande sont les mêmes qu'en langage SQL standard.

Si une liste de variables est utilisée comme target, les valeurs sélectionnées doivent correspondre exactement à la structure de la cible, ou une erreur d'exécution se produit. Lorsqu'une variable d'enregistrement est la cible, elle se configure automatiquement sur le type de ligne des colonnes de résultat de la requête.

La clause INTO peut apparaître presque partout dans l'instruction SELECT. Elle apparaît habituellement juste après la clause SELECT ou juste avant la clause FROM. Ainsi, elle apparaît juste avant ou juste après la liste select_expressions.

Si la requête ne renvoie aucune ligne, des valeurs NULL sont affectées à target. Si la requête renvoie plusieurs lignes, la première ligne est affectée à target et les autres sont ignorées. À moins que l'instruction contienne une commande ORDER BY, la première ligne n'est pas déterministe.

Pour déterminer si l'affectation a retourné au moins une ligne, utilisez la variable FOUND spéciale.

SELECT INTO customer_rec * FROM cust WHERE custname = lname; IF NOT FOUND THEN RAISE EXCEPTION 'employee % not found', lname; END IF;

Pour tester si un résultat d'enregistrement est null, vous pouvez utiliser l'opérateur conditionnel IS NULL. Aucune méthode ne permet de déterminer si des lignes supplémentaires peuvent avoir été ignorées. L'exemple suivant traite le cas où aucune ligne n'a été renvoyée.

CREATE OR REPLACE PROCEDURE select_into_null(return_webpage OUT varchar(256)) AS $$ DECLARE customer_rec RECORD; BEGIN SELECT INTO customer_rec * FROM users WHERE user_id=3; IF customer_rec.webpage IS NULL THEN -- user entered no webpage, return "http://" return_webpage = 'http://'; END IF; END; $$ LANGUAGE plpgsql;

No-op

L'instruction no-op (NULL;) est une instruction d'espace réservé qui ne fait rien. Une instruction no-op peut indiquer qu'une branche d'une chaîne IF-THEN-ELSE est vide.

NULL;

Instructions SQL dynamiques

Pour générer des commandes dynamiques qui peuvent impliquer différentes tables ou différents types de données chaque fois qu'elles sont exécutées à partir d'une procédure stockée PL/pgSQL, utilisez l'instruction EXECUTE.

EXECUTE command-string [ INTO target ];

Dans le code précédent, command-string est une expression de chaîne (de type texte) qui contient la commande à exécuter. Cette valeur command-string est envoyée au moteur SQL. Aucune substitution des variables PL/pgSQL n'est effectuée sur la chaîne de commande. Les valeurs des variables doivent être insérées dans la chaîne de commande lorsqu'elle est construite.

Note

Vous ne pouvez pas utiliser les instructions COMMIT et ROLLBACK depuis SQL dynamique. Pour plus d'informations sur l'utilisation des instructions COMMIT et ROLLBACK dans une procédure stockée, consultez Gestion des transactions.

Lorsque vous utilisez des commandes dynamiques, vous devez souvent traiter l'échappement des guillemets simples. Nous vous recommandons de placer le texte fixe entre guillemets dans le corps de votre fonction en utilisant des guillemets dollar. Les valeurs dynamiques à insérer dans une requête construite nécessitent un traitement spécial, car elles peuvent contenir elles-mêmes des guillemets. L'exemple suivant suppose des guillemets dollar pour la fonction dans son ensemble, afin que les guillemets n'aient pas besoin d'être doublés.

EXECUTE 'UPDATE tbl SET ' || quote_ident(colname) || ' = ' || quote_literal(newvalue) || ' WHERE key = ' || quote_literal(keyvalue);

L'exemple précédent illustre les fonctions quote_ident(text) et quote_literal(text). Cet exemple transmet des variables contenant des identifiants de colonne et de table à la fonction quote_ident. Il transmet également des variables qui contiennent des chaînes littérales dans la commande construite à la fonction quote_literal. Ces deux fonctions prennent les mesures appropriées pour retourner le texte d'entrée entre guillemets doubles ou simples respectivement, avec n'importe quels caractères spéciaux intégrés correctement échappés.

Les guillemets dollar sont utiles uniquement pour citer du texte fixe. N'écrivez pas l'exemple précédent dans le format suivant.

EXECUTE 'UPDATE tbl SET ' || quote_ident(colname) || ' = $$' || newvalue || '$$ WHERE key = ' || quote_literal(keyvalue);

En effet, cet exemple s'interrompt si le contenu de newvalue contient $$. Le même problème s'applique à tout autre délimiteur de guillemets dollar que vous pouvez choisir. Pour citer en toute sécurité du texte qui n'est pas connu à l'avance, utilisez la fonction quote_literal.

Return

L'instruction RETURN retourne à l'appelant à partir d'une procédure stockée.

RETURN;

Vous en trouverez un exemple ci-dessous.

CREATE OR REPLACE PROCEDURE return_example(a int) AS $$ BEGIN FOR b in 1..10 LOOP IF b < a THEN RAISE INFO 'b = %', b; ELSE RETURN; END IF; END LOOP; END; $$ LANGUAGE plpgsql;

Conditions : IF

L'instruction conditionnelle IF peut prendre les formes suivantes dans le langage PL/pgSQL qu'Amazon Redshift utilise :

  • IF ... THEN

    IF boolean-expression THEN statements END IF;

    Vous en trouverez un exemple ci-dessous.

    IF v_user_id <> 0 THEN UPDATE users SET email = v_email WHERE user_id = v_user_id; END IF;
  • IF ... THEN ... ELSE

    IF boolean-expression THEN statements ELSE statements END IF;

    Vous en trouverez un exemple ci-dessous.

    IF parentid IS NULL OR parentid = '' THEN return_name = fullname; RETURN; ELSE return_name = hp_true_filename(parentid) || '/' || fullname; RETURN; END IF;
  • IF ... THEN ... ELSIF ... THEN ... ELSE

    Le mot clé ELSIF peut également être orthographié ELSEIF.

    IF boolean-expression THEN statements [ ELSIF boolean-expression THEN statements [ ELSIF boolean-expression THEN statements ...] ] [ ELSE statements ] END IF;

    Vous en trouverez un exemple ci-dessous.

    IF number = 0 THEN result := 'zero'; ELSIF number > 0 THEN result := 'positive'; ELSIF number < 0 THEN result := 'negative'; ELSE -- the only other possibility is that number is null result := 'NULL'; END IF;

Conditions : CASE

L'instruction conditionnelle CASE peut prendre les formes suivantes dans le langage PL/pgSQL qu'Amazon Redshift utilise :

  • CASE simple

    CASE search-expression WHEN expression [, expression [ ... ]] THEN statements [ WHEN expression [, expression [ ... ]] THEN statements ... ] [ ELSE statements ] END CASE;

    Une instruction CASE simple fournit une exécution conditionnelle basée sur l'égalité des opérandes.

    La valeur search-expression est évaluée une fois et comparée successivement à chaque expression dans les clauses WHEN. Si une correspondance est trouvée, les instructions (statements) correspondantes s'exécutent, puis le contrôle passe à l'instruction qui suit END CASE. Les expressions WHEN suivantes ne sont pas évaluées. Si aucune correspondance n'est trouvée, les instructions (statements) ELSE s'exécutent. Toutefois, en l'absence de ELSE, une exception CASE_NOT_FOUND est levée.

    Vous en trouverez un exemple ci-dessous.

    CASE x WHEN 1, 2 THEN msg := 'one or two'; ELSE msg := 'other value than one or two'; END CASE;
  • CASE avec recherche

    CASE WHEN boolean-expression THEN statements [ WHEN boolean-expression THEN statements ... ] [ ELSE statements ] END CASE;

    La forme de CASE avec recherche fournit une exécution conditionnelle basée sur la véracité des expressions booléennes.

    Chaque expression booléenne (boolean-expression) de la clause WHEN est évaluée à son tour jusqu'à ce qu'une d'elles fournisse la valeur true. Les instructions correspondantes s'exécutent alors, puis le contrôle passe à l'instruction qui suit END CASE. Les expressions WHEN suivantes ne sont pas évaluées. Si aucun résultat true n'est trouvé, les instructions (statements) ELSE sont exécutées. Toutefois, en l'absence de ELSE, une exception CASE_NOT_FOUND est levée.

    Vous en trouverez un exemple ci-dessous.

    CASE WHEN x BETWEEN 0 AND 10 THEN msg := 'value is between zero and ten'; WHEN x BETWEEN 11 AND 20 THEN msg := 'value is between eleven and twenty'; END CASE;

Boucles

Les instructions de boucle peuvent prendre les formes suivantes dans le langage PL/pgSQL qu'Amazon Redshift utilise :

  • Boucle simple

    [<<label>>] LOOP statements END LOOP [ label ];

    Une boucle simple définit une boucle sans condition qui se répète indéfiniment jusqu'à ce qu'elle soit terminée par une instruction EXIT ou RETURN. Une étiquette facultative peut être utilisée par les instructions EXIT et CONTINUE au sein de boucles imbriquées pour spécifier à quelle boucle l'instruction EXIT ou CONTINUE fait référence.

    Vous en trouverez un exemple ci-dessous.

    CREATE OR REPLACE PROCEDURE simple_loop() LANGUAGE plpgsql AS $$ BEGIN <<simple_while>> LOOP RAISE INFO 'I am raised once'; EXIT simple_while; RAISE INFO 'I am not raised'; END LOOP; RAISE INFO 'I am raised once as well'; END; $$;
  • Quitter une boucle

    EXIT [ label ] [ WHEN expression ];

    Si aucune étiquette (label) n'est présente, la boucle la plus interne est interrompue et l'instruction qui suit le END LOOP s'exécute alors. Si une étiquette label est présente, ce doit être l'étiquette du niveau actuel ou d'un niveau extérieur de la boucle imbriquée ou du bloc. La boucle ou le bloc nommé est alors interrompu et le contrôle passe à l'instruction située après le END correspondant à la boucle ou au bloc.

    Si WHEN est spécifié, la sortie de la boucle se produit uniquement si l'expression est vraie. Dans le cas contraire, le contrôle passe à l'instruction qui suit EXIT.

    Vous pouvez utiliser EXIT avec tous les types de boucle. Il n'est pas limité à une utilisation avec des boucles sans condition.

    Lorsqu'il est utilisé avec un bloc BEGIN, EXIT passe le contrôle à l'instruction suivante située après la fin du bloc. Une étiquette doit être utilisée à cet effet. Une instruction EXIT sans étiquette n'est jamais considérée comme correspondant à un bloc BEGIN.

    Vous en trouverez un exemple ci-dessous.

    CREATE OR REPLACE PROCEDURE simple_loop_when(x int) LANGUAGE plpgsql AS $$ DECLARE i INTEGER := 0; BEGIN <<simple_loop_when>> LOOP RAISE INFO 'i %', i; i := i + 1; EXIT simple_loop_when WHEN (i >= x); END LOOP; END; $$;
  • Continuer une boucle

    CONTINUE [ label ] [ WHEN expression ];

    Si aucune étiquette (label) n'est fournie, l'exécution saute à l'itération suivante de la boucle la plus interne. Ainsi, toutes les instructions restantes du corps de la boucle sont ignorées. Le contrôle retourne ensuite à l'expression de contrôle de boucle (le cas échéant) pour déterminer si une autre itération de boucle est requise. Si une étiquette (label) est présente, elle spécifie l'étiquette de la boucle dont l'exécution est poursuivie.

    Si l'instruction WHEN est spécifiée, l'itération suivante de la boucle est commencée seulement si l'expression est vraie. Dans le cas contraire, le contrôle passe à l'instruction qui suit CONTINUE.

    Vous pouvez utiliser CONTINUE avec tous les types de boucle. Il n'est pas limité à une utilisation avec des boucles sans condition.

    CONTINUE mylabel;
  • Boucle WHILE

    [<<label>>] WHILE expression LOOP statements END LOOP [ label ];

    L'instruction WHILE répète une série d'instructions tant que l'expression booléenne (boolean-expression) équivaut à true. L'expression est vérifiée juste avant chaque entrée dans le corps de la boucle.

    Vous en trouverez un exemple ci-dessous.

    WHILE amount_owed > 0 AND gift_certificate_balance > 0 LOOP -- some computations here END LOOP; WHILE NOT done LOOP -- some computations here END LOOP;
  • Boucle FOR (variante avec entier)

    [<<label>>] FOR name IN [ REVERSE ] expression .. expression LOOP statements END LOOP [ label ];

    La boucle FOR (variante avec entier) crée une boucle qui effectue des itérations sur une plage de valeurs entières. Le nom de la variable est défini automatiquement de type entier et existe uniquement au sein de la boucle. Toute définition existante du nom de la variable est ignorée au sein de la boucle. Les deux expressions qui donnent les limites inférieure et supérieure de la plage sont évaluées une fois à l'entrée de la boucle. Si vous spécifiez REVERSE, la valeur du pas est soustraite au lieu d'être ajoutée après chaque itération.

    Si la limite inférieure est supérieure à la limite supérieure (ou inférieure à celle-ci si REVERSE est utilisé), le corps de la boucle ne s'exécute pas. Aucune erreur n'est levée.

    Si une étiquette est attachée à la boucle FOR, Vous pouvez référencer la variable entière de boucle avec un nom complet en utilisant cette étiquette.

    Vous en trouverez un exemple ci-dessous.

    FOR i IN 1..10 LOOP -- i will take on the values 1,2,3,4,5,6,7,8,9,10 within the loop END LOOP; FOR i IN REVERSE 10..1 LOOP -- i will take on the values 10,9,8,7,6,5,4,3,2,1 within the loop END LOOP;
  • Boucle FOR (variante avec ensemble de résultats)

    [<<label>>] FOR target IN query LOOP statements END LOOP [ label ];

    La cible (target) est une variable d'enregistrement ou une liste séparée par des virgules de variables scalaires. La cible se voit successivement attribuer chaque ligne résultant de la requête et le corps de la boucle est exécuté pour chaque ligne.

    La boucle FOR (variante avec ensemble de résultats) permet à une procédure stockée d'itérer sur les résultats d'une requête et de manipuler ces données en conséquence.

    Vous en trouverez un exemple ci-dessous.

    CREATE PROCEDURE cs_refresh_reports() AS $$ DECLARE reports RECORD; BEGIN FOR reports IN SELECT * FROM cs_reports ORDER BY sort_key LOOP -- Now "reports" has one record from cs_reports EXECUTE 'INSERT INTO ' || quote_ident(reports.report_name) || ' ' || reports.report_query; END LOOP; RETURN; END; $$ LANGUAGE plpgsql;
  • Boucle FOR avec instruction SQL dynamique

    [<<label>>] FOR record_or_row IN EXECUTE text_expression LOOP statements END LOOP;

    Une boucle FOR avec instruction SQL dynamique permet à une procédure stockée d'itérer sur les résultats d'une requête dynamique et de manipuler ces données en conséquence.

    Vous en trouverez un exemple ci-dessous.

    CREATE OR REPLACE PROCEDURE for_loop_dynamic_sql(x int) LANGUAGE plpgsql AS $$ DECLARE rec RECORD; query text; BEGIN query := 'SELECT * FROM tbl_dynamic_sql LIMIT ' || x; FOR rec IN EXECUTE query LOOP RAISE INFO 'a %', rec.a; END LOOP; END; $$;

Curseurs

Plutôt que d'exécuter immédiatement une requête entière, vous pouvez configurer un curseur. Un curseur encapsule une requête et lit le résultat de la requête en traitant plusieurs lignes à la fois. Une des raisons de procéder ainsi est d'éviter un dépassement de mémoire lorsque le résultat contient un grand nombre de lignes. Une autre raison est de retourner une référence à un curseur qu'une procédure stockée a créé, ce qui permet à l'appelant de lire les lignes. Cette approche fournit une méthode efficace pour retourner de grands ensembles de lignes à partir de procédures stockées.

Pour utiliser les curseurs dans une procédure stockée NONATOMIC, placez la boucle du curseur entre START TRANSACTION...COMMIT.

Pour configurer un curseur, commencez par déclarer une variable de curseur. Tout accès aux curseurs dans PL/pgSQL passe par les variables de curseur, qui sont toujours du type de données spécial refcursor. Un type de données refcursor détient simplement une référence à un curseur.

Vous pouvez créer une variable de curseur en la déclarant en tant que variable de type refcursor. Vous pouvez également utiliser la syntaxe de déclaration de curseur suivante.

name CURSOR [ ( arguments ) ] FOR query ;

Dans ce qui précède, arguments (le cas échéant) est une liste séparée par des virgules de paires nom-type de données (name datatype) dont chacune définit les noms à remplacer par des valeurs de paramètres dans la requête (query). Les valeurs réelles à substituer à ces noms sont spécifiées ultérieurement, à l'ouverture du curseur.

Des exemples sont fournis ci-dessous.

DECLARE curs1 refcursor; curs2 CURSOR FOR SELECT * FROM tenk1; curs3 CURSOR (key integer) IS SELECT * FROM tenk1 WHERE unique1 = key;

Ces trois variables ont le type de données refcursor, mais la première peut être utilisée avec une requête quelconque. Au contraire, une requête entièrement spécifiée est liée à la seconde, et une requête paramétrée est liée à la dernière. La valeur key est remplacée par une valeur de paramètre entière à l'ouverture du curseur. La variable curs1 est dite non liée, car elle n'est liée à aucune requête particulière.

Avant de pouvoir utiliser un curseur pour récupérer des lignes, vous devez l'ouvrir. Le langage PL/pgSQL a trois formes d'instruction OPEN, dont deux utilisent des variables de curseur non liées, tandis que la troisième utilise une variable de curseur liée :

  • Ouverture pour sélection : la variable de curseur est ouverte et reçoit la requête spécifiée à exécuter. Le curseur ne doit pas être déjà ouvert. De plus, il doit avoir été déclaré en tant que curseur non lié (c'est-à-dire, en tant que simple variable refcursor). La requête SELECT est traitée de la même manière que les autres instructions SELECT dans le langage PL/pgSQL.

    OPEN cursor_name FOR SELECT ...;

    Vous en trouverez un exemple ci-dessous.

    OPEN curs1 FOR SELECT * FROM foo WHERE key = mykey;
  • Ouverture pour exécution : la variable de curseur est ouverte et reçoit la requête spécifiée à exécuter. Le curseur ne doit pas être déjà ouvert. De plus, il doit avoir été déclaré en tant que curseur non lié (c'est-à-dire, en tant que simple variable refcursor). La requête est spécifiée en tant qu'expression de chaîne de la même manière que dans la commande EXECUTE. Cette approche est flexible et permet à la requête de varier d'une exécution à l'autre.

    OPEN cursor_name FOR EXECUTE query_string;

    Vous en trouverez un exemple ci-dessous.

    OPEN curs1 FOR EXECUTE 'SELECT * FROM ' || quote_ident($1);
  • Ouverture d'un curseur lié : cette forme d'instruction OPEN est utilisée pour ouvrir une variable de curseur à laquelle sa requête a été liée quand elle a été déclarée. Le curseur ne doit pas être déjà ouvert. La liste des expressions des valeurs d'argument réelles doit apparaître si et seulement si le curseur a été déclaré comme acceptant des arguments. Ces valeurs sont substituées dans la requête.

    OPEN bound_cursor_name [ ( argument_values ) ];

    Vous en trouverez un exemple ci-dessous.

    OPEN curs2; OPEN curs3(42);

Une fois qu'un curseur a été ouvert, vous pouvez l'utiliser à l'aide des instructions décrites ci-après. Ces instructions ne sont pas tenues de figurer dans la procédure stockée qui a ouvert le curseur. Vous pouvez retourner une valeur refcursor à partir d'une procédure stockée et laisser l'appelant opérer sur le curseur. Tous les portails sont implicitement fermés à la fin de la transaction. Par conséquent, vous pouvez utiliser une valeur refcursor pour référencer un curseur ouvert seulement jusqu'à la fin de la transaction.

  • L'instruction FETCH extrait la ligne suivante du curseur dans une cible. Cette cible peut être une variable de ligne, une variable d'enregistrement ou une liste séparée par des virgules de variables simples, comme avec SELECT INTO. Comme avec SELECT INTO, vous pouvez vérifier la variable spéciale FOUND pour voir si une ligne a été obtenue.

    FETCH cursor INTO target;

    Vous en trouverez un exemple ci-dessous.

    FETCH curs1 INTO rowvar;
  • L'instruction CLOSE ferme le portail sous-jacent à un curseur ouvert. Vous pouvez utiliser cette instruction pour libérer des ressources avant la fin de la transaction. Vous pouvez également utiliser cette instruction pour libérer la variable de curseur, qui pourra ainsi être de nouveau ouverte.

    CLOSE cursor;

    Vous en trouverez un exemple ci-dessous.

    CLOSE curs1;

RAISE

Utilisez l'instruction RAISE level pour signaler les messages et les erreurs.

RAISE level 'format' [, variable [, ...]];

Les niveaux possibles sont NOTICE, INFO, LOG, WARNING et EXCEPTION. EXCEPTION lève une erreur, ce qui entraîne normalement l'annulation de la transaction en cours. Les autres niveaux génèrent seulement des messages de différents niveaux de priorité.

Dans la chaîne de format, % est remplacé par la représentation de chaîne de l'argument facultatif suivant. Écrivez %% pour obtenir un % littéral. Actuellement, les arguments facultatifs doivent être des variables simples et non pas des expressions, et le format doit être un littéral de chaîne simple.

Dans l'exemple suivant, la valeur de v_job_id remplace le % dans la chaîne.

RAISE NOTICE 'Calling cs_create_job(%)', v_job_id;

Utilisez l'instruction RAISE pour relancer l'exception capturée par un bloc de gestion des exceptions. Cette déclaration n'est valable que dans les blocs de gestion des exceptions des procédures stockées en mode NONATOMIC.

RAISE;

Contrôle de transaction

Vous pouvez utiliser les instructions de contrôle de transaction du langage PL/pgSQL qu'Amazon Redshift utilise. Pour plus d'informations sur l'utilisation des instructions COMMIT, ROLLBACK et TRUNCATE dans une procédure stockée, consultez Gestion des transactions.

Dans les procédures stockées en mode NONATOMIC, utilisez START TRANSACTION pour démarrer un bloc de transaction.

START TRANSACTION;
Note

L'instruction PL/pgSQL START TRANSACTION est différente de la commande SQL START TRANSACTION pour les raisons suivantes :

  • Dans les procédures stockées, START TRANSACTION n'est pas synonyme de BEGIN.

  • L'instruction PL/pgSQL ne prend pas en charge les mots-clés facultatifs de niveau d'isolement et d'autorisations d'accès.