2012-10-09 4 views
0
CREATE TABLE TEST_CASE 
    (
    ID NUMBER(19,2), 
    CURRENCY_TYPE VARCHAR2(30), 
    PAIDAMT NUMBER(19,2), 
    RECVDAMT NUMBER(19,2), 
    AMTDUE NUMBER, 
    TRANSACTION_DATE VARCHAR2(30) 
); 

J'ai créé une procédure pour récupérer les champs qui ont AMT en leur nom. Mais la procédure montre une erreur lors de l'exécution, je n'arrive pas à comprendre pourquoi cette erreur génère.problème avec le curseur dans la procédure

create or replace procedure chk_amt 
(
    vtbl varchar2 
) 
as 
tblcursor sys_refcursor; 
tblsqlstr varchar2(1000); 
importedrows VARCHAR2(1000); 
BEGIN 
    tblsqlstr := 'Select COLUMN_NAME from user_tab_columns where table_name= '|| vtbl ||' and COLUMN_NAME like upper(''%AMT%'')' ; 
    OPEN tblcursor for tblsqlstr; 
loop 
fetch tblcursor into importedrows; 
DBMS_OUTPUT.PUT_LINE(importedrows); 
EXIT WHEN tblcursor%NOTFOUND; 
end loop; 
CLOSE tblcursor; 
end; 
/
erreur

est

ORA-00904: "TEST_CASE": invalid identifier 
ORA-06512: at "***.CHK_AMT", line 11 
ORA-06512: at line 2 

Comment puis-je résoudre cette erreur ??

Répondre

2

Ajouter des guillemets simples autour vtbl à votre déclaration dynamique, il devient: -

tblsqlstr := 'Select COLUMN_NAME from user_tab_columns where table_name= '''|| vtbl ||''' and COLUMN_NAME like upper(''%AMT%'')' ; 

Cela signifie que lorsque votre code est exécuté, si vtbl a une table_a de valeur, la déclaration qui est en fait courir sera être 'table_a' plutôt que table_a.

N.B. Veillez à ne pas rendre cette procédure publique, car elle est vulnérable à l'injection sql. Idéalement, vous devriez utiliser une variable de liaison à la place. Exemple ci-dessous: -

CREATE OR REPLACE PROCEDURE chk_amt(vtbl VARCHAR2) AS 
tblcursor SYS_REFCURSOR; 
tblsqlstr VARCHAR2(1000); 
importedrows VARCHAR2(1000); 
BEGIN 
tblsqlstr := 'Select COLUMN_NAME from user_tab_columns where table_name= :val_bnd and COLUMN_NAME like upper(''%AMT%'')'; 
OPEN tblcursor FOR tblsqlstr USING vtbl; 
LOOP 
    FETCH tblcursor 
     INTO importedrows; 
    dbms_output.put_line(importedrows); 
    EXIT WHEN tblcursor%NOTFOUND; 
END LOOP; 
CLOSE tblcursor; 
END; 
2

Sauf si vous avez une raison particulière d'utiliser SQL dynamique, il est beaucoup plus facile d'utiliser SQL statique. Il est également généralement plus facile d'utiliser des curseurs implicites, sauf si vous avez des raisons pour lesquelles les curseurs explicites sont avantageux. Étant donné que l'extrait de code ne montre pas besoin d'utiliser SQL ou curseurs explicites, il peut être simplifié à

create or replace procedure chk_amt 
(
    vtbl varchar2 
) 
as 
BEGIN 
    FOR columns IN (SELECT column_name 
        FROM user_tab_columns 
        WHERE table_name = vtbl 
        AND column_name LIKE '%AMT%') 
    LOOP 
    DBMS_OUTPUT.PUT_LINE(columns.column_name); 
    END LOOP; 
end; 
dynamique

L'erreur spécifique que vous obtenez est le résultat de concaténer la variable vtbl dans votre instruction SQL dynamique . Si vous voulez concaténer la chaîne comme ça, vous devrez mettre une seule citation avant et après la variable dans la chaîne et vous devrez échapper toutes les guillemets dans le nom de la table (bien sûr, il y a probablement des guillemets simples dans un nom de table). Si vous devez utiliser SQL dynamique, vous seriez bien mieux servis en utilisant des variables liées à la place

tblsqlstr := 'Select COLUMN_NAME 
       from user_tab_columns 
       where table_name= :1 
        and COLUMN_NAME like upper(''%AMT%'')' ; 
OPEN tblcursor for tblsqlstr using vtbl; 

En plus d'être plus efficace et d'éviter le risque d'attaques par injection SQL, qui évite la nécessité d'échapper aux données dans votre région variables et évite le besoin d'ajouter des guillemets supplémentaires à la chaîne.