Как назначить несколько значений для строки в оракуле - PullRequest
3 голосов
/ 11 ноября 2009

Я хочу присвоить множественные значения переменной и использовать эту переменную в предложении where.

Например:

declare

    v_filename varchar2(300) := ''('filename1','filename2')'';
    cnt number;

begin

    select count(*) into cnt from table_name
    where filename in v_filename;

end;

Пожалуйста, сообщите.

Спасибо, Дипак

Ответы [ 4 ]

3 голосов
/ 11 ноября 2009

у вас есть в основном 2 варианта. 1. Используйте динамический запрос 2. Используйте коллекции

  1. С помощью динамического запроса вы динамически создаете запрос во время выполнения и затем запускаете его:

DECLARE
  v_filename VARCHAR2(300) := '(''ALL_VIEWS'', ''ALL_TABLES'')'; 
--double quotes inside a string
  cnt NUMBER;

BEGIN
execute immediate 'SELECT COUNT(*) INTO :cnt FROM all_views
   WHERE view_name IN ' || v_filename
   into cnt;
  dbms_output.put_line('counted: ' || cnt);
END;
/

Преимущества: легко писать, особенно для коротких запросов, быстро Недостатки: возможен SQL INJECTION в случаях, когда вы неправильно вставляете пользовательский ввод в строку запроса, жесткий анализ каждый раз при изменении списка имен файлов

  1. Используйте коллекции. Вы создаете тип коллекции, затем заполняете ее и используете в качестве псевдотаблицы.

create type tt_strings as table of varchar2(30);

declare 
  cnt NUMBER;
  v_condition tt_strings;

begin
  v_condition := tt_strings();
  v_condition.extend;
  v_condition(1) := 'ALL_VIEWS';
  v_condition.extend;
  v_condition(2) := 'ALL_TABLES';

  SELECT COUNT(*)
    INTO cnt
    FROM all_views o, TABLE(v_condition) x
   WHERE x.column_value = o.VIEW_NAME;
  dbms_output.put_line('counted: ' || cnt);
end;
/

Преимущества: Безопасный, обслуживаемый для больших коллекций с более чем 2 элементами Недостатки: вам нужно создать тип, сложнее для кодирования (сначала), немного медленнее (что в 99% случаев не имеет значения)

2 голосов
/ 11 ноября 2009

Я бы рекомендовал прочитать Динамические IN-Lists

EXECUTE IMMEDIATE также возможен, но я бы не рекомендовал его, если вы не проверяете строку IN.

Только что написал по-быстрому (использовал первый метод, представленный в «Динамических IN-Lists»):

CREATE OR REPLACE TYPE t_varchar_tab AS TABLE OF VARCHAR2 (4000);
CREATE OR REPLACE FUNCTION in_list (p_in_list  IN  VARCHAR2) RETURN t_varchar_tab
AS
  l_tab   t_varchar_tab := t_varchar_tab();
  l_text  VARCHAR2(32767) := p_in_list || ',';
  l_idx   NUMBER;
BEGIN
  LOOP
    l_idx := INSTR(l_text, ',');
    EXIT WHEN NVL(l_idx, 0) = 0;
    l_tab.extend;
    l_tab(l_tab.last) := TRIM(SUBSTR(l_text, 1, l_idx - 1));
    l_text := SUBSTR(l_text, l_idx + 1);
  END LOOP;

  RETURN l_tab;
END;

SELECT * FROM TABLE(in_list('filename1,filename2'));
SELECT COUNT(*) INTO cnt FROM table_name WHERE filename IN (SELECT * FROM TABLE(in_list(v_filename)));
1 голос
/ 11 ноября 2009

В качестве альтернативы «ВЫПОЛНИТЬ НЕМЕДЛЕННЫЙ», вы можете использовать как, например,

declare

    v_filename varchar2(300) := '(''filename1'',''filename2'')';
    cnt number;

begin

    select count(*) into cnt from table_name
    where v_filename like '%'''||filename||'''%';

end;

Обратите внимание, что парентезы и запятая в v_filename предназначены только для удобства чтения. Это ни в коем случае не идеальное решение, поскольку оно предполагает, что имена файлов в вашей таблице не содержат специальных символов; Это также плохо с точки зрения производительности, если в столбце имени файла есть индекс (который не используется таким образом).

1 голос
/ 11 ноября 2009

Вы должны поместить весь запрос в строку, а затем выполнить эту строку с помощью EXECUTE IMMEDIATE ( см. Документы ).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...