2017-01-27 7 views
0

Im пытается выполнить ниже раздел кода, но получить ошибку ORA-00904.ORA-00904 - «NORM»: неверный идентификатор - строка в динамическом sql

Declare 
i_status varchar2(4) := 'NORM'; 
vsql varchar2(4000); 
... 
... 
Begin 
... 
...<Part of larger dynamic sql> 
    If i_status is not null Then 
    vSql := vSql || ' And account.astatus = ' ||i_status|| ''; 
    End if; 

execute immediate (vSql) into tmp,ssn; 

<Do something with tmp, ssn> 

End; 

Исключение возникает в строке "выполнить немедленно" с ошибкой ОРА-00904 - "NORM": неверный идентификатор

колонка account.astatus имеет тип CHAR (4 байта)

I предположим, что проблема заключается в том, что я пытаюсь передать строчную переменную NORM в предложении where без добавления кавычек ''. Как обойти эту проблему?

Спасибо.

ответ

4

Простой ответ заключается в использовании переменных связывания, что означает, что вы избегаете всей тернистой проблемы с SQL-инъекцией, которую вы открываете себе, когда вы жестко кодируете свои переменные в динамический sql. Вы также избавляете себя от необходимости определять, как включать одиночные кавычки, чтобы обойти строку, в которой отсутствует ваш динамический sql.

Использование переменных связывания ваш код становится:

Declare 
    i_status varchar2(4) := 'NORM'; 
    vsql varchar2(4000); 
    ... 
    ... 
Begin 
    ... 
    ...<Part of larger dynamic sql> 

    If i_status is not null Then 
    vSql := vSql || ' And account.astatus = :i_status'; 
    End if; 

    execute immediate (vSql) into tmp,ssn using i_status; 

    <Do something with tmp, ssn> 

End; 
+0

спасибо. Работал как шарм. – MrM

4

Вы можете легко вырыть в свой код и проверить, где проблема существует печатая ваш VSQL перед его выполнением.

Declare 
    i_status varchar2(10) := 'NORM'; 
    vsql varchar2(4000):= 'Select * from dual where 1=3'; 

    Begin 

     If i_status is not null Then 
     vSql := vSql || ' And account.astatus = ' ||i_status|| ''; 
     End if; 

     dbms_output.put_line(vSql); 

     --execute immediate (vSql) into tmp,ssn;   

    End; 

При выполнении этого блока вы можете увидеть утверждение, которое становится генерируемый, который показывает:

Select * от двойного где 1 = 3 И account.astatus = NORM

Теперь вы можете легко заметить, что ваш account.astatus = NORM не подходит, поэтому его можно заменить на:

i_status varchar2(10) := '''NORM'''; 

или с помощью Q цитаты:

i_status varchar2(10) := q'['NORM']'; 

Тем не менее, что упомянутый Boneist является лучшей практикой, которая позволяет избежать инъекции SQL.