0
votes

Oracle - Nom de colonne SQL dynamique dans la fusion / instruction

J'ai la procédure ci-dessous sans message d'erreur: xxx pré>

Lorsque j'essaie de l'exécuter avec des valeurs pour les paramètres d'entrée, je reçois une erreur de compilateur: p>

Connecting to the database localDB.
ORA-00933: SQL command not properly ended
ORA-06512: at "RTT.INSERT_OR_UPD_MOVEMENT_BASELINES_PLANNED_WEIGHT_PROC", line 17
ORA-06512: at line 12
Process exited.


1 commentaires

Votre problème réside dans le demi-point que vous avez ajouté à votre texte plsql_block, FWIW.


3 Réponses :


0
votes

Cette partie est définitivement FISHY:

   values ( ' || p_id || ', to_date(''' || to_char(p_date) || '''), ' || p_planned_value || ')


2 commentaires

N'est pas le problème que j'ai peur. Obtenir toujours la même erreur. Aussi, le P_Date est une date, donc je ne sais pas pourquoi nous devons la convertir en une date à nouveau?


Oh aussi, les valeurs que je suis inséré vous conduiront à la relève de la mise à jour et non à l'insert. Connaissez-vous un moyen d'imprimer la SQL dynamique afin que nous puissions identifier quelque chose de mal tout de suite?



2
votes

Vous devez toujours être prudent tout en utilisant dynamic sql. Premièrement, il est préférable de vérifier si une instruction SQL statique fonctionne bien, puis essayez de le convertir en modifiant les pièces dynamiques. En outre, un dbms_output code> avant exécuté immédiat code> vous aide à savoir si le SQL préparé est syntaxiquement correct. Deuxièmement, les valeurs de concaténation sont sujettes à injection SQL em> et doivent être évitées.Prréférance option consiste à utiliser des variables de liaison avec l'option code> à l'aide de code> d'exécution immédiate code>.

Etant donné que p_planned_value code> est défini comme un numéro, il implique que le type de données de toutes les colonnes que vous prévoyez de mettre à jour / insertion sera des entiers. Je l'ai utilisé en conséquence dans mon exemple dans la démo. Si ce n'est pas le cas, vous devrez repenser comment vous allez définir les paramètres de la procédure de travail pour les autres cas tels que Date code> DataTypes. P>

CREATE OR REPLACE PROCEDURE insert_or_upd_movement_baselines_planned_weight_proc (
     p_id                 IN VARCHAR2,
     p_date               IN DATE,
     p_planned_col_name   IN VARCHAR2,
     p_planned_value      IN NUMBER
)
     AS
  plsql_block   VARCHAR2(4000);
     BEGIN
plsql_block := 'merge into MOVEMENT_BASELINES mb using 
 ( select :id as movement_id,:dt as movement_date from dual
  ) s ON ( mb.movement_id = s.movement_id  
              and mb.movement_date = s.movement_date )
     when matched then update set '
          || p_planned_col_name || ' = ' || p_planned_value || 
 ' when not matched then insert (MOVEMENT_ID, MOVEMENT_DATE,'
          || p_planned_col_name || ')
       values (:id,:dt,:value)';

EXECUTE IMMEDIATE plsql_block
              USING p_id,p_date,p_id,p_date,p_planned_value;

END insert_or_upd_movement_baselines_planned_weight_proc;
/


1 commentaires

Oui, ils seront tous numéros :) Merci ça marche et merci pour les informations DBMS_Output, je cherchais à imprimer avec Oracle



0
votes

Il s'agit d'un addendum à la réponse de Kaushik, où ils déclarent (tout à fait correctement, sinon dans tant de mots) que votre déclaration est totalement vulnérable à l'injection SQL.

J'écrirais votre procédure comme suit: P>

CREATE OR REPLACE PROCEDURE insert_or_upd_movement_baselines_planned_weight_proc(p_id               IN VARCHAR2,
                                                                                 p_date             IN DATE,
                                                                                 p_planned_col_name IN VARCHAR2,
                                                                                 p_planned_value    IN NUMBER) AS
  v_sql              CLOB;
  v_planned_col_name VARCHAR2(32);
BEGIN
  v_planned_col_name := dbms_assert.simple_sql_name(p_planned_col_name);

  v_sql := 'MERGE INTO movement_baselines tgt'||CHR(10)||
           'USING (SELECT :p_id movement_id,'||CHR(10)||
           '              :p_date movement_date,'||CHR(10)||
           '              :p_planned_value planned_value'||CHR(10)||
           '       FROM   dual) src'||CHR(10)||
           'ON (tgt.movement_id = src.movement_id AND tgt.movement_date = src.movement_date)'||CHR(10)||
           'WHEN NOT MATCHED THEN'||CHR(10)||
           '  INSERT (tgt.movement_id, tgt.movement_date, tgt.'||v_planned_col_name||')'||CHR(10)||
           '  VALUES (src.movement_id, src.movement_date, src.movement_date)'||CHR(10)||
           'WHEN MATCHED THEN'||CHR(10)||
           '  UPDATE'||CHR(10)||
           '  SET    tgt.'||v_planned_col_name||' = src.planned_value';


  dbms_output.put_line('merge statement: ' || chr(10) || v_sql);

  EXECUTE IMMEDIATE v_sql
    USING p_id, p_date, p_planned_value;

END;
/


0 commentaires