web-dev-qa-db-fra.com

Utilisation de variables de liaison avec la clause SELECT INTO dynamique dans PL/SQL

J'ai une question concernant l'endroit où les variables de liaison peuvent être utilisées dans une instruction SQL dynamique en PL/SQL.

Par exemple, je sais que cela est valide:

CREATE OR REPLACE FUNCTION get_num_of_employees (p_loc VARCHAR2, p_job VARCHAR2) 
RETURN NUMBER
IS
  v_query_str VARCHAR2(1000);
  v_num_of_employees NUMBER;
BEGIN
  v_query_str := 'SELECT COUNT(*) FROM emp_' 
                 || p_loc
                 || ' WHERE job = :bind_job';                           
  EXECUTE IMMEDIATE v_query_str
    INTO v_num_of_employees
    USING p_job;
  RETURN v_num_of_employees;
END;
/

Je me demandais si vous pouviez utiliser une variable de liaison dans une instruction select comme celle-ci

CREATE OR REPLACE FUNCTION get_num_of_employees (p_loc VARCHAR2, p_job VARCHAR2) 
RETURN NUMBER
IS
  v_query_str VARCHAR2(1000);
  v_num_of_employees NUMBER;
BEGIN
  v_query_str := 'SELECT COUNT(*) INTO :into_bind FROM emp_' 
                 || p_loc
                 || ' WHERE job = :bind_job';                           
  EXECUTE IMMEDIATE v_query_str
    USING out v_num_of_employees, p_job;
  RETURN v_num_of_employees;
END;
/

Remarque J'ai utilisé une instruction SELECT INTO comme chaîne dyamic et une variable de liaison dans la clause INTO.

Je suis actuellement en voyage et je n'aurai pas accès à mon ordinateur à la maison pendant quelques jours, mais cela me harcèle depuis un moment. J'ai essayé de lire la référence PL/SQL mais ils n'ont pas d'exemple de sélection comme celle-ci.

Merci

42
BYS2

Non, vous ne pouvez pas utiliser les variables de liaison de cette façon. Dans votre deuxième exemple, :into_bind dans v_query_str est simplement un espace réservé pour la valeur de la variable v_num_of_employees. Votre déclaration select se transformera en quelque chose comme:

SELECT COUNT(*) INTO  FROM emp_...

parce que la valeur de v_num_of_employees est null à EXECUTE IMMEDIATE.

Votre premier exemple présente la manière correcte de lier la valeur de retour à une variable.

Modifier

L’affiche originale a modifié le deuxième bloc de code auquel je me réfère dans ma réponse en utilisant le paramètre OUT en mode v_num_of_employees au lieu du mode par défaut IN. Cette modification rend les deux exemples fonctionnellement équivalents.

27
user272735

À mon avis, un bloc PL/SQL dynamique est quelque peu obscur. Bien que très flexible, il est également difficile à régler, difficile à déboguer et à comprendre ce qui se passe ... Mon vote va vers votre première option,

EXECUTE IMMEDIATE v_query_str INTO v_num_of_employees USING p_job;

Les deux utilisent des variables de liaison, mais d’abord, pour moi, est plus redéfinissable et ajustable que l’option @jonearles. 

27
Aitor

Placez l'instruction select dans un bloc PL/SQL dynamique.

CREATE OR REPLACE FUNCTION get_num_of_employees (p_loc VARCHAR2, p_job VARCHAR2) 
RETURN NUMBER
IS
  v_query_str VARCHAR2(1000);
  v_num_of_employees NUMBER;
BEGIN
  v_query_str := 'begin SELECT COUNT(*) INTO :into_bind FROM emp_' 
                 || p_loc
                 || ' WHERE job = :bind_job; end;';
  EXECUTE IMMEDIATE v_query_str
    USING out v_num_of_employees, p_job;
  RETURN v_num_of_employees;
END;
/
18
Jon Heller

La variable de liaison peut être utilisée dans une requête SQL Oracle avec la clause "in".

Fonctionne en 10g; Je ne sais pas pour les autres versions.

La variable de liaison est varchar jusqu'à 4000 caractères.

Exemple: Variable de liaison contenant une liste de valeurs séparées par des virgules, par ex.

: bindvar = 1,2,3,4,5 

select * from mytable
  where myfield in
    (
      SELECT regexp_substr(:bindvar,'[^,]+', 1, level) items
      FROM dual
      CONNECT BY regexp_substr(:bindvar, '[^,]+', 1, level) is not null
    );

(Même information que j'ai posté ici: Comment spécifiez-vous la clause IN dans une requête dynamique utilisant une variable? )

0
Kat