Переменная связывания для запросов IN - PullRequest
2 голосов
/ 13 мая 2011

при использовании переменной связывания, она не получает значения

eg,, SELECT * FROM EMP WHERE USER IN (:VALUES)

Если я использую этот запрос, он не выполнен

передача значений напрямую

SELECT * FROM EMP WHERE USER IN (+ arraylist +) нормально работает

========================================

вот пример кода

string[] Myarray = ListVal.split(','); Query = "SELECT * FROM EMP WHERE USER IN (:VALUES)"

OracleParameter Param = { new OracleParameter (":VALUES",OracleDBType.Array)

};

Param[0].value = Myarray;

using(dr = OracleFactory.ExecuteReader(CommandType.Text,Query,true,Param)) {

}

при выполнении этого я получаю исключение, подобное

Недопустимая привязка параметров ParameterName VALUES

Ответы [ 4 ]

3 голосов
/ 13 мая 2011

Вам нужно передать значения в виде массива и немного изменить запрос.Следующий код для ODP.NET.Я не знаю, можно ли это сделать с устаревшими драйверами Microsoft от Oracle.

Сначала вам нужно определить тип таблицы (например, для VARCHAR ):

CREATE TYPE varchar_table AS TABLE OF VARCHAR2(2000); 

Когда вы создаете параметр для запроса, объявите его как ассоциативный массив PL / SQL:

OracleParameter param1 = new OracleParameter(); 
param1.OracleDbType = OracleDbType.Varchar2; 
param1.CollectionType = OracleCollectionType.PLSQLAssociativeArray; 

Затем присвойте несколько значений:

param1 = new string[2] { "johnp", "billt" }; 

И ваш запрос нуждаетсяактерский состав:

SELECT * FROM EMP WHERE USER IN (TABLE(CAST(:values AS varchar_table)))
1 голос
/ 13 мая 2011

К сожалению, вы не можете передавать массивы для связывания переменных.

Ваши единственные опции - это вставка в запрос списка, разделенного запятыми, или запись собственного помощника / оболочки, который автоматически переписывает ваш оператор в

IN (:value1, :value2, :value3...)

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

0 голосов
/ 22 мая 2019

( Также кросс-пост на )

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

Я мало работаю с Oracle, но, как и в SQL Server, этоКажется, что для передачи табличного параметра вам нужно иметь соответствующий UDT (пользовательская таблица), к которому у вас есть разрешения EXECUTE (я могу ошибаться).Это означает, что другие ответы, предполагающие использование встроенного SYS UDT, идут с некоторым грузом, и я не мог понять, действительно ли возможно передать таблицу чему-то, что не является хранимой процедурой PL / SQL в текущей версииODP.net.

Во-вторых, решение для разбора строк является препятствием по всем очевидным причинам (невозможно кэшировать план выполнения или как его называет Oracle, плохо масштабируется и т. д.).

Так что я потратил довольно много времени, пытаясь выполнить предложение IN, используя табличный параметр в datamart, на который у меня есть только разрешение READ, прежде чем я столкнулся с ослепительной вспышкой очевидного (в ASP)..net на форуме не меньше).Оказывается, Oracle поддерживает Xml-запросы «изначально», поэтому вместо передачи массива значений вы можете передать список XML (если это все, что вам нужно).Опять же, я могу ошибаться, но он обрабатывается как допустимый параметр связывания, и это пример того, как его просто использовать (vb.net, ADO.net, ODP.net с использованием пакета NuGet):

Dim xe As New XElement("l", New XElement("i", "ITEM-A"), New XElement("i", "ITEM-B"))
Using conn As New OracleConnection(myConnectionString)
    conn.Open()
    Using cmd As OracleCommand = conn.CreateCommand()
        cmd.CommandType = CommandType.Text
        Dim query As String
        query = "  SELECT s.FOO, q.BAR " & vbCrLf
        query &= " FROM TABLE1 s LEFT OUTER JOIN " & vbCrLf
        query &= "      TABLE2 q ON q.ID = s.ID " & vbCrLf
        query &= " WHERE (COALESCE(q.ID, 'NULL') NOT LIKE '%OPTIONAL%') AND "
        query &= "       (s.ID IN ("
        query &= "                      SELECT stid "
        query &= "                      FROM XMLTable('/l/i' PASSING XMLTYPE(:stid) COLUMNS stid VARCHAR(32) PATH '.')"
        query &= "                 )"
        query &= "        )"
        cmd.CommandText = query
        Dim parameter As OracleParameter = cmd.Parameters.Add("stid", OracleDbType.NVarchar2, 4000)
        parameter.Value = xe.ToString
        Using r As OracleDataReader = cmd.ExecuteReader
            While r.Read()
                //Do something
            End While
        End Using
    End Using
    conn.Close()

Это скорее наблюдение, чем тщательно изученное решение, поэтому, пожалуйста, прокомментируйте, если есть что-то неуместное в этом.

РЕДАКТИРОВАТЬ.При использовании этого метода, по-видимому, существует ограничение в 4000 символов (2000, если NVARCHAR), поэтому мне пришлось наблюдать за своей страницей.Информативное сообщение об ошибке, которое вы получите, если перейдете, «ORA-01460: запрошено невыполненное или необоснованное преобразование» *

0 голосов
/ 13 мая 2011

Прежде всего, я серьезно сомневаюсь, что запрос не выполнен.

Вернее, если он действительно не был выполнен , тогда вы получите исключение и спросите очто.

Я думаю, что вы говорите, что вы не получите никаких результатов, и это совсем другое.

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

В конечном итоге вы выполняете оператор IN только с одним значением.Какое именно это значение зависит от коллекции, которую вы передаете, и от того, как ее можно преобразовать в соответствующий тип для механизма запросов.Может случиться так, что вы в конечном итоге вызовете .ToString() для коллекции и вставите ее туда.

В любом случае это невозможно сделать.Вы должны пойти по пути конкатенации строк.

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

Другими словами, вы должны сделать это для коллекции из 4 элементов:

SELECT * FROM EMP WHERE USER IN (:V1, :V2, :V3, :V4)

, а затем привязать каждый параметр к одному из элементов коллекции.Тем не менее, вам все равно придется строить SQL динамически.

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