2016-03-04 2 views
1

Возможно ли получить значение из поля записи с помощью переменной, чтобы его можно было переслать? Если да, то как я могу это сделать?PL SQL Как я могу указать поле записи, используя переменную

Когда я делаю это, он работает.

DECLARE 
    dev_day JX_DATA_20160301%ROWTYPE; 
    ichar varchar2(3); 
BEGIN 
    SELECT * into dev_day FROM JX_DATA_20160301 WHERE did=100; 
    ichar:='H01'; 
    dbms_output.put_line(dev_day.H01); 
END; 

Но когда я изменить его таким образом:

DECLARE 
    dev_day JX_DATA_20160301%ROWTYPE; 
    ichar varchar2(3); 
BEGIN 
    SELECT * into dev_day FROM JX_DATA_20160301 WHERE did=100; 
    ichar:='H01'; 
    dbms_output.put_line(dev_day.ichar); 
END; 

Я получаю сообщение об ошибке:

ORA-06550: linia 7, kolumna 32: PLS-00302: component 
'ICHAR' must be declared ORA-06550: linia 7, kolumna 3: PL/SQL: 
Statement ignored 
06550. 00000 - "line %s, column %s:\n%s" 

ответ

1

Согласно AskTom, вы должны хранить запись в упаковке:

CREATE PACKAGE temp_storage_pkg 
AS 
    JX_DATA_REC JX_DATA_20160301%ROWTYPE; 
END; 
/

DECLARE 
    ichar CHAR(3) := 'H01'; 
    value VARCHAR2(4000); 
BEGIN 
    SELECT * INTO temp_storage_pkg.JX_DATA_REC FROM JX_DATA_20160301 WHERE did=100; 
    EXECUTE IMMEDIATE 'BEGIN :x := temp_storage_pkg.JX_DATA_REC.' || ichar || '; END;' 
    USING OUT value; 
    DBMS_OUTPUT.PUT_LINE(value); 
END; 
/
0

Вы не можете напрямую r efer в поле записи, используя имя переменной. Вы можете сделать это с помощью the dbms_sql package, но это кажется излишним:

DECLARE 
    l_column_name user_tab_columns.column_name%type; 
    l_cursor integer; 
    l_cols integer; 
    l_rows integer; 
    l_desc dbms_sql.desc_tab; 
    l_value varchar2(4000); 
BEGIN 
    l_column_name := 'H01'; 

    l_cursor := dbms_sql.open_cursor; 
    dbms_sql.parse(l_cursor, 'SELECT * FROM JX_DATA_20160301 WHERE did=:did', 
    dbms_sql.native); 
    dbms_sql.bind_variable(l_cursor, 'did', 100); 
    l_rows := dbms_sql.execute(l_cursor); 

    dbms_sql.describe_columns(c => l_cursor, col_cnt => l_cols, 
    desc_t => l_desc); 

    for i in 1..l_cols loop 
    dbms_sql.define_column(l_cursor, i, l_value, 4000); 
    end loop; 

    while dbms_sql.fetch_rows(l_cursor) > 0 loop 
    for i in 1..l_cols loop 
     if l_desc(i).col_name = l_column_name then 
     dbms_sql.column_value(l_cursor, i, l_value); 
     dbms_output.put_line(l_value); 
     end if; 
    end loop; 
    end loop; 

    dbms_sql.close_cursor(l_cursor); 
END; 
/

Вы можете использовать более конкретный тип данных для l_value, если вы знаете, столбец всегда будет рядом, скажем. Или вы можете иметь переменную каждого возможного типа и выбирать, какую использовать на основе типа данных, которую вы можете получить от l_desc(i).

Но если вы знаете структуру таблицы, вы можете переключиться на значение переменной вместо:

DECLARE 
    dev_day JX_DATA_20160301%ROWTYPE; 
    ichar varchar2(3); 
BEGIN 
    SELECT * into dev_day FROM JX_DATA_20160301 WHERE did=100; 
    ichar:='H01'; 
    case ichar 
    when 'H01' then 
     dbms_output.put_line(dev_day.h01); 
    when 'H02' then 
     dbms_output.put_line(dev_day.h02); 
    -- ... etc, for each column you might want 
    end case;  
END; 
/
+0

Пользуясь случаем - когда была моя первая мысль, но я думал, что я мог бы сделать это лучше. Кажется, это лучшее решение. благодаря –

1

Вы можете перевести ваш запрос в XMLtype. А затем работайте с XmlType.

Например:

DECLARE 
-- Local variables here 
xml_t   xmltype; 
ichar CHAR(3) := 'H01'; 
l_refcursor SYS_REFCURSOR; 
BEGIN 
OPEN l_refcursor FOR 
     SELECT * FROM JX_DATA_20160301 WHERE did=100; 
xml_t := XMLTYPE(l_refcursor); 
dbms_output.put_line(xml_t.extract('//'||ichar||'/text()').getStringVal); 
END; 
Смежные вопросы