Вызов функции в строке в процедуре Oracle
Я пишу приложение, используя Oracle 10g.
Я сейчас сталкиваюсь с этой проблемой. Я беру в "имя файла" в качестве параметра типа varchar2.
Пример значения, которое может содержать имя файла: "TEST || to_char(sysdate, 'DDD')'.
В этой процедуре я хочу получить значение этого имени файла, как в TEST147. Когда я пишу:
select filename
into ffilename
from dual;
Я получаю значение ffilename = TEST || to_char(sysdate, 'DDD') имеет смысл. Но как я могу обойти эту проблему и вызвать функцию в строковом значении?
Помощь приветствуется. Благодарю.
2 ответа
Достаточно просто динамически выполнить строку...
create or replace function fmt_fname (p_dyn_string in varchar2)
return varchar2
is
return_value varchar2(128);
begin
execute immediate 'select '||p_dyn_string||' from dual'
into return_value;
return return_value;
end fmt_fname;
/
Проблема возникает, когда ваша строка содержит литералы со страшными кавычками...
SQL> select fmt_fname('TEST||to_char(sysdate, 'DDD')') from dual
2 /
select fmt_fname('TEST||to_char(sysdate, 'DDD')') from dual
*
ERROR at line 1:
ORA-00907: missing right parenthesis
SQL>
Поэтому мы должны избегать апострофов, всех из них, включая те, которые вы не включили в опубликованную строку:
SQL> select * from t34
2 /
ID FILENAME
---------- ------------------------------
1 APC001
2 XYZ213
3 TEST147
SQL> select * from t34
2 where filename = fmt_fname('''TEST''||to_char(sysdate, ''DDD'')')
3 /
ID FILENAME
---------- ------------------------------
3 TEST147
SQL>
РЕДАКТИРОВАТЬ
Справедливости ради, я чувствую, что должен отметить, что решение Тони работает так же хорошо:
SQL> create or replace function fmt_fname (p_dyn_string in varchar2)
2 return varchar2
3 is
4 return_value varchar2(128);
5 begin
6 execute immediate 'begin :result := ' || p_dyn_string || '; end;'
7 using out return_value;
8 return return_value;
9 end;
10 /
Function created.
SQL> select fmt_fname('''TEST''||to_char(sysdate, ''DDD'')') from dual
2 /
FMT_FNAME('''TEST''||TO_CHAR(SYSDATE,''DDD'')')
--------------------------------------------------------------------------------
TEST147
SQL>
На самом деле, избегая SELECT на DUAL, это, вероятно, лучше.
Строковое значение в вашем примере является недопустимым выражением; должно быть: "ТЕСТ" || to_char (sysdate, 'DDD')
Чтобы оценить, что вы могли бы сделать это:
execute immediate 'begin :result := ' || filename || '; end;'
using out v_string;
Тогда v_string будет содержать 'TEST147'.