sqlplus - использование переменной связывания в предложении "IN" - PullRequest
3 голосов
/ 11 февраля 2011

Я устанавливаю переменную связывания в блоке PL / SQL и пытаюсь использовать ее в выражении IN другого запроса.Примерно так:

variable x varchar2(255)

declare
    x varchar2(100);
begin
    for r in (select id from other_table where abc in ('&val1','&val2','&val3') ) loop
    x := x||''''||r.id||''',';
    end loop;
    --get rid of the trailing ','
    x:= substr(x,1,length(x)-1);

    select x into :bind_var from dual;
end;
/

print :bind_var;

select *
from some_table
where id in (:bind_var);

И я получаю сообщение об ошибке (ORA-01722: Неверное число) в запросе, который пытается использовать переменную связывания в списке «IN».

оператор print дает '123','345', что я и ожидаю.

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

(с использованием Oracle 10g)


Уточнение:

Это что-то вроде примирения.Я хочу запустить

select *
from some_table
where id in (select id from other_table where abc in ('&val1','&val2','&val3'))

до того, как основная часть скрипта (здесь не изображена) удаляет целую кучу записей.Я хочу запустить его снова после этого, чтобы убедиться, что записи в some_table НЕ были удалены.Однако данные в other_table ДЕЛАЕТСЯ в результате этого процесса, поэтому я не могу просто обратиться к данным в other_table, потому что там ничего нет.Мне нужен способ сохранить значения other_table.id, чтобы потом можно было проверить родительские записи.

Ответы [ 5 ]

6 голосов
/ 12 февраля 2011

Я бы хранил other_table.id в таблице PL / SQL и впоследствии ссылался на эту таблицу в запросе:

type t_id_table is table OF other_table.id%type index by binary_integer;
v_table t_id_table;

-- fill the table
select id
bulk collect into v_table
from other_table 
where abc in ('&val1','&val2','&val3');     

-- then at a later stage...    

select *
from some_table st
,    table(cast(v_table AS t_id_table)) idt
where st.id = idt.id;
1 голос
/ 12 февраля 2011

Я бы использовал для этой цели глобальную временную таблицу

create global temporary table gtt_ids( id number ) ;

, затем

...
for r in (select id from other_table where ... ) loop
   insert into gtt_ids(id) values (r.id) ;
end loop;
...

и в конце

select *
from some_table
where id in (select id from gtt_ids);
1 голос
/ 11 февраля 2011

Нельзя использовать значения через запятую в одной переменной связывания.

Вы можете сказать:

select * from some_table where id in (:bind_var1, :bind_var2)

хотя

Вам лучше использовать что-то вроде:

select * from some_table where id in ("select blah blah blah...");
0 голосов
/ 12 февраля 2011

изменил цикл для использования listagg (к сожалению, это будет работать только в 11gr2).

но для переменной в списке я использовал регулярное выражение для достижения цели (но до 10g вы можете использовать substr , чтобы сделать то же самое), это снято с asktom вопрос связан.

    variable bind_var varchar2(255)
variable dataSeperationChar varchar2(255)

declare
    x varchar2(100);
begin

select listagg(id,',')  within group(order by id) idList
into x
  from(select level id 
         from dual  
        connect by level < 100 ) 
where id in (&val1,&val2,&val3) ;
    select x into :bind_var from dual;
    :dataSeperationChar := ',';
end;
/

print :bind_var;

/



select *
  from (
        select level id2
          from dual
         connect by level < 100
        )
    where id2 in(
            select  -- transform the comma seperated string into a result set        
            regexp_substr(:dataSeperationChar||:bind_var||','
                        , '[^'||:dataSeperationChar||']+'
                      ,1
                      ,level)    as parsed_value
            from dual
            connect by level <= length(regexp_replace(:bind_var, '([^'||:dataSeperationChar||'])', '')) + 1    
    )
;

/*
values of 1,5, and 25

BIND_VAR
------
1,5,25

ID2                    
---------------------- 
1                      
5                      
25   
*/

EDIT


Упс только что заметил, что вы отметили 10g, единственное, что нужно сделать, это НЕ использовать listagg, который я сделал в начале

0 голосов
/ 12 февраля 2011

Хорошо, у меня есть некрасивое решение, которое также использует переменные подстановки ...

col idList NEW_VALUE v_id_list /* This is NEW! */
variable x varchar2(255)
declare
    x varchar2(100);
begin
    for r in (select id from other_table where abc in ('&val1','&val2','&val3') ) loop
    x := x||''''||r.id||''',';
    end loop;
    --get rid of the trailing ','
    x:= substr(x,1,length(x)-1);

    select x into :bind_var from dual;
end;
/

print :bind_var;

select :x idList from dual;  /* This is NEW! */

select *
from some_table
where id in (&idList);  /* This is CHANGED! */

Это работает, но я приму ответ от кого-то другого, если оно будет более элегантным.

...