Вставить список значений в предложении where из c #, используя oracle db - PullRequest
0 голосов
/ 01 апреля 2011

Я уже некоторое время искал способ выполнить оператор выбора в базе данных oracle, которая содержит произвольное количество элементов в предложении where. В принципе, я хочу сделать что-то вроде этого:

select * from my_table
where my_col in (:inputListHere)

Оглядываясь вокруг, я нашел следующие решения, ни одно из которых, похоже, не работает должным образом:

  1. Использование динамического sql и просто вставить список в виде строки с разделенными запятыми элементами.
    Работает только для коротких списков. Длинные списки превышают ограничение в 4000 символов для литералов командной строки. (Кстати: мне не нужно беспокоиться об атаках с использованием SQL-инъекций, так что в принципе динамический SQL-код был бы вариантом).

  2. Использование ассоциативных массивов в хранимых процессах. Из того, что я мог найти, единственный способ использовать ассоциативные массивы в хранимом процессе - это перебирать их, но это дало бы ужасную производительность, когда я хочу получить все отличающиеся вхождения элементов в списке в таблице.

  3. Использование массивов связывания с сохраненным процессом. Та же проблема: поскольку хранимый процесс вызывается один раз для каждого элемента в массиве связывания, производительность ужасна.

  4. Вставка списка, который я хочу использовать в предложении where, в базу данных заранее и затем выполнение запроса, который имеет что-то вроде select list_items from tmp_list_store вместо :inputListHere. Производительность здесь оказалась лучше, чем для варианта 2 и 3., но хуже, чем для варианта 1, и дополнительным недостатком является то, что пользователь, выполняющий запрос, должен иметь доступ на запись к этой одной таблице в базе данных, даже если он просто хочет читать с БД.

Если у вас есть какие-либо лучшие варианты или идеи, как улучшить один из этих вариантов, мы будем очень благодарны.

Ответы [ 2 ]

2 голосов
/ 01 апреля 2011

Отправить список значений в виде строки XML.

Пример обработки XML с использованием XMLTABLE:

 SELECT cid1 FROM SomeTable 
    WHERE cid2 in ( 
        SELECT val 
            FROM XMLTABLE('/list/val' 
                PASSING xmltype('<list><val>a1</val><val>a2</val><val>a3</val></list>')
                COLUMNS val VARCHAR2(32) PATH '/'));
    );

Или:

  1. Создать новый тип оракула TABLE OF NUMBER / или VARCHAR
  2. Создать новую функцию оракула, которая будет разбери свой список в таблицу чисел или VARCHAR
  3. Тогда вы можете сделать что-то вроде этого:

    ВЫБРАТЬ cid1 ИЗ SomeTable ГДЕ cid2 в (ВЫБРАТЬ * ИЗ таблицы (LIST_TO_NUMBER_TABLE (p_YourValuesList))));

Из .NET просто передайте значение параметра в этом формате: 12,33,54,35,65

Вот пример функции list_to_table:

create or replace FUNCTION LIST_TO_NUMBER_TABLE
(
    p_LIST IN VARCHAR2
)
RETURN NUMBER_TABLE PIPELINED
AS

    STRING_       LONG := p_LIST || ',';
    COMMAINDEX_   PLS_INTEGER;
    INDEX_        PLS_INTEGER := 1;

BEGIN
    LOOP
        COMMAINDEX_ := INSTR(STRING_, ',', INDEX_);
        EXIT WHEN COMMAINDEX_ = 0;
        PIPE ROW (TO_NUMBER(SUBSTR(STRING_, INDEX_, COMMAINDEX_ - INDEX_)));
        INDEX_ := COMMAINDEX_ + 1;
    END LOOP;
    RETURN;
END;
0 голосов
/ 02 мая 2012

Получив немного больше знаний по базам данных за последние полгода, я пришел к следующему выводу: Что касается решения предложенной мною проблемы, то ответ ХАБЖАН в дополнение к предложенным мною вариантам является, пожалуй, наиболее разумным решением.
Причина, по которой ни одно из этих решений не работает, заключается в том, что правильный ответ, я думаю, состоит в том, что если у вас есть пара тысяч элементов для передачи, вы должны иметь их не как параметры, а как значения в отдельной таблице в базе данных. , В противном случае дизайн, вероятно, следует пересмотреть. В этом смысле вариант 4, вероятно, наиболее близок к правильному ответу, но не имеет проблемы вообще, потому что вы улучшаете свой дизайн, вероятно, лучший ответ.

...