ORA-01008: не все переменные связаны. Они связаны
Я столкнулся с проблемой Oracle, для которой я до сих пор не смог найти причину.
Следующий запрос работает в Oracle SQL-разработчике, но при работе в .NET он бросает:
ORA-01008: не все переменные связаны
Я пробовал:
- Изменение типа данных Oracle для lot_priority (Varchar2 или int32).
- Изменение типа данных .NET для lot_priority (строка или int).
- Одно имя переменной привязки используется дважды в запросе. Это не проблема в моей
другие запросы, которые используют одну и ту же связанную переменную более чем в одном
но, чтобы быть уверенным, что я попытался сделать второй экземпляр его
собственную переменную с другим именем и привязкой ее отдельно.
- Несколько различных способов привязки переменных (см. комментарий;
также другие).
- Перемещение вызова bindByName().
- Замена каждой связанной переменной на литерал. У меня были две отдельные переменные, вызывающие проблему (: lot_pri и: lot_priprc). Были некоторые незначительные изменения, которые я не могу запомнить между ними. Переход к литералам заставил запрос работать, но им нужно работать со связыванием.
Ниже следуют запрос и код. Имена переменных изменены для защиты невинных:
SELECT rf.myrow floworder, rf.stage, rf.prss,
rf.pin instnum, rf.prid, r_history.rt, r_history.wt
FROM
(
SELECT sub2.myrow, sub2.stage, sub2.prss, sub2.pin, sub2.prid
FROM (
SELECT sub.myrow, sub.stage, sub.prss, sub.pin,
sub.prid, MAX(sub.target_rn) OVER (ORDER BY sub.myrow) target_row
,sub.hflag
FROM (
WITH floc AS
(
SELECT flow.prss, flow.seq_num
FROM [email protected] flow
WHERE flow.parent_p = :lapp
AND flow.prss IN (
SELECT r_priprc.prss
FROM [email protected] r_priprc
WHERE priprc = :lot_priprc
)
AND rownum = 1
)
SELECT row_number() OVER (ORDER BY pp.seq_num, rpf.seq_num) myrow,
rpf.stage, rpf.prss, rpf.pin,
rpf.itype, hflag,
CASE WHEN rpf.itype = 'SpecialValue'
THEN rpf.instruction
ELSE rpf.parent_p
END prid,
CASE WHEN rpf.prss = floc.prss
AND rpf.seq_num = floc.seq_num
THEN row_number() OVER (ORDER BY pp.seq_num, rpf.seq_num)
END target_rn
FROM floc, [email protected] rpf
LEFT OUTER JOIN [email protected] pp
ON (pp.prss = rpf.prss)
WHERE pp.priprc = :lot_priprc
ORDER BY pp.seq_num, rpf.seq_num
) sub
) sub2
WHERE sub2.myrow >= sub2.target_row
AND sub2.hflag = 'true'
) rf
LEFT OUTER JOIN [email protected] r_history
ON (r_history.lt = :lt
AND r_history.pri = :lot_pri
AND r_history.stage = rf.stage
AND r_history.curp = rf.prid
)
ORDER BY myrow
public void runMyQuery(string lot_priprc, string lapp, string lt, int lot_pri) {
Dictionary<int, foo> bar = new Dictionary<int, foo>();
using(var con = new OracleConnection(connStr)) {
con.Open();
using(var cmd = new OracleCommand(sql.rtd_get_flow_for_lot, con)) { // Query stored in sql.resx
try {
cmd.BindByName = true;
cmd.Prepare();
cmd.Parameters.Add(new OracleParameter("lapp", OracleDbType.Varchar2)).Value = lapp;
cmd.Parameters.Add(new OracleParameter("lot_priprc", OracleDbType.Varchar2)).Value = lot_priprc;
cmd.Parameters.Add(new OracleParameter("lt", OracleDbType.Varchar2)).Value = lt;
// Also tried OracleDbType.Varchar2 below, and tried passing lot_pri as an integer
cmd.Parameters.Add(new OracleParameter("lot_pri", OracleDbType.Int32)).Value = lot_pri.ToString();
/*********** Also tried the following, more explicit code rather than the 4 lines above: **
OracleParameter param_lapp
= cmd.Parameters.Add(new OracleParameter("lapp", OracleDbType.Varchar2));
OracleParameter param_priprc
= cmd.Parameters.Add(new OracleParameter("lot_priprc", OracleDbType.Varchar2));
OracleParameter param_lt
= cmd.Parameters.Add(new OracleParameter("lt", OracleDbType.Varchar2));
OracleParameter param_lot_pri
= cmd.Parameters.Add(new OracleParameter("lot_pri", OracleDbType.Varchar2));
param_lapp.Value = lastProcedureStackProcedureId;
param_priprc.Value = lotPrimaryProcedure;
param_lt.Value = lotType;
param_lot_pri.Value = lotPriority.ToString();
//***************************************************************/
var reader = cmd.ExecuteReader();
while(reader.Read()) {
// Get values from table (Never reached)
}
}
catch(OracleException e) {
// ORA-01008: not all variables bound
}
}
}
Почему Oracle утверждает, что не все переменные связаны?
Ответы
Ответ 1
Я нашел, как запустить запрос без ошибок, но я не решаюсь назвать это "решением", не понимая при этом основной причины.
Это более похоже на начало моего фактического запроса:
-- Comment
-- More comment
SELECT rf.flowrow, rf.stage, rf.process,
rf.instr instnum, rf.procedure_id, rtd_history.runtime, rtd_history.waittime
FROM
(
-- Comment at beginning of subquery
-- These two comment lines are the problem
SELECT sub2.flowrow, sub2.stage, sub2.process, sub2.instr, sub2.pid
FROM ( ...
Второй набор комментариев выше, в начале подзапроса, был проблемой. После удаления запрос выполняется. Другие комментарии в порядке.
Это не вопрос какой-либо изгоев или отсутствующей новой строки, заставляя прокомментировать следующую строку, потому что следующая строка - это SELECT. Отсутствующий выбор приведет к другой ошибке, чем "не все связанные переменные".
Я спросил и нашел одного сотрудника, который столкнулся с этим - комментарии, вызывающие ошибки запроса - несколько раз.
Кто-нибудь знает, как это может быть причиной? Я понимаю, что самое первое, что СУБД будет делать с комментариями, это увидеть, содержат ли они подсказки, а если нет, удалите их во время разбора. Как обычный комментарий, не содержащий необычных символов (только буквы и период), вызывает ошибку? Bizarre.
Ответ 2
Я знаю, что это старый вопрос, но он не был правильно рассмотрен, поэтому я отвечаю на него тем, кто может столкнуться с этой проблемой.
По умолчанию Oracle ODP.net связывает переменные по положению и рассматривает каждую позицию как новую переменную.
Рассмотрение каждой копии как другой переменной и ее значение несколько раз является обходным решением и болью, как упомянуто furman87, и может привести к ошибкам, если вы пытаетесь переписать запрос и перемещать вещи.
Правильный способ - установить для свойства BindByName свойства OracleCommand значение true:
var cmd = new OracleCommand(cmdtxt, conn);
cmd.BindByName = true;
Вы также можете создать новый класс для инкапсуляции OracleCommand, чтобы значение BindByName было истинным при создании экземпляра, поэтому вам не нужно устанавливать значение каждый раз. Об этом говорится в этом сообщении
Ответ 3
У вас есть две ссылки на переменную привязки: lot_priprc - в то время как она должна требовать только установить значение переменной один раз и связать ее в обоих местах, у меня были проблемы, когда это не сработало и пришлось обрабатывать каждый копировать как другую переменную. Боль, но это сработало.
Ответ 4
В вопросе комментариев Чарльза: чтобы ухудшить ситуацию, пусть
:p1 = 'TRIALDEV'
с помощью параметра команды, затем выполните
select T.table_name as NAME, COALESCE(C.comments, '===') as DESCRIPTION
from all_all_tables T
Inner Join all_tab_comments C on T.owner = C.owner and T.table_name = C.table_name
where Upper(T.owner)=:p1
order by T.table_name
558 line(s) affected. Processing time: 00:00:00.6535711
и при изменении строковой строки от === до ---
select T.table_name as NAME, COALESCE(C.comments, '---') as DESCRIPTION
[...from...same-as-above...]
ORA-01008: not all variables bound
Оба оператора отлично работают в SQL Developer. Укороченный код:
Using con = New OracleConnection(cs)
con.Open()
Using cmd = con.CreateCommand()
cmd.CommandText = cmdText
cmd.Parameters.Add(pn, OracleDbType.NVarchar2, 250).Value = p
Dim tbl = New DataTable
Dim da = New OracleDataAdapter(cmd)
da.Fill(tbl)
Return tbl
End Using
End Using
с использованием Oracle.ManagedDataAccess.dll версии 4.121.2.0 с настройками по умолчанию в VS2015 на платформе .Net 4.61.
Итак, где-то в цепочке вызовов может быть синтаксический анализатор, который слишком агрессивно ищет однострочные комментарии, начинающиеся с - в commandText. Но даже если бы это было правдой, сообщение об ошибке "не все связанные переменные", по крайней мере, вводит в заблуждение.
Ответ 5
Это ошибка в управляемом ODP.net - 'Ошибка 21113901: MANAGED ODP.NET RAISE ORA-1008 ИСПОЛЬЗОВАНИЕ ОДИНОЧНОГО ЦИТИРОВАННОГО CONST + BIND VAR IN SELECT' исправлено в патче 23530387, замененном патчем 24591642
Ответ 6
Пришел сюда для поиска справки, так как получил ту же ошибку, что и оператор, указанный ниже, проходя через курс Udemy:
INSERT INTO departments (department_id, department_name)
values( &dpet_id, '&dname');
Раньше я мог запускать операторы с переменными замещения. Комментарий Чарльза Бернса о возможности достижения сервером некоторого порога при воссоздании переменных заставил меня выйти из системы и перезапустить SQL Developer. Заявление прошло успешно после входа в систему.
Думал, что я поделюсь с кем-нибудь другим, занимающимся здесь, с ограниченным объемом вопросов, как у меня.
Ответ 7
Решение в моей ситуации было похоже на Чарльза Бернса; и проблема была связана с комментариями кодов SQL.
Я создавал (или обновлял, скорее) уже функционирующий отчет SSRS с Oracle datasource. Я добавил еще несколько параметров в отчет, протестировал его в Visual Studio, он отлично работает, поэтому я развернул его на сервере отчетов, а затем, когда отчет будет выполнен, отчет на сервере я получил сообщение об ошибке:
"ORA-01008: не все переменные связаны"
Я попробовал несколько разных вещей (файл TNSNames.ora, установленный на сервере, Удаленные комментарии одиночной строки, Проверка сопоставления данных набора данных). Что я понял, мне пришлось удалить блок комментариев непосредственно после WHERE keyword
. Сообщение об ошибке было разрешено после перемещения блока комментариев после WHERE CLAUSE conditions
. У меня есть и другие комментарии в коде. Это произошло только после того, как ключевое слово WHERE вызвало ошибку.
SQL с ошибкой: "ORA-01008: не все переменные связаны"...
WHERE
/*
OHH.SHIP_DATE BETWEEN TO_DATE('10/1/2018', 'MM/DD/YYYY') AND TO_DATE('10/31/2018', 'MM/DD/YYYY')
AND OHH.STATUS_CODE<>'DL'
AND OHH.BILL_COMP_CODE=100
AND OHH.MASTER_ORDER_NBR IS NULL
*/
OHH.SHIP_DATE BETWEEN :paramStartDate AND :paramEndDate
AND OHH.STATUS_CODE<>'DL'
AND OHH.BILL_COMP_CODE IN (:paramCompany)
AND LOAD.DEPART_FROM_WHSE_CODE IN (:paramWarehouse)
AND OHH.MASTER_ORDER_NBR IS NULL
AND LOAD.CLASS_CODE IN (:paramClassCode)
AND CUST.CUST_CODE || '-' || CUST.CUST_SHIPTO_CODE IN (:paramShipto)
SQL успешно выполняется на сервере отчетов...
WHERE
OHH.SHIP_DATE BETWEEN :paramStartDate AND :paramEndDate
AND OHH.STATUS_CODE<>'DL'
AND OHH.BILL_COMP_CODE IN (:paramCompany)
AND LOAD.DEPART_FROM_WHSE_CODE IN (:paramWarehouse)
AND OHH.MASTER_ORDER_NBR IS NULL
AND LOAD.CLASS_CODE IN (:paramClassCode)
AND CUST.CUST_CODE || '-' || CUST.CUST_SHIPTO_CODE IN (:paramShipto)
/*
OHH.SHIP_DATE BETWEEN TO_DATE('10/1/2018', 'MM/DD/YYYY') AND TO_DATE('10/31/2018', 'MM/DD/YYYY')
AND OHH.STATUS_CODE<>'DL'
AND OHH.BILL_COMP_CODE=100
AND OHH.MASTER_ORDER_NBR IS NULL
*/
Вот как выглядит экран сопоставления параметров набора данных.
![enter image description here]()
Ответ 8
У меня была бы аналогичная проблема в устаревшем приложении, но параметр "-" был строковым.
Пример:.
Dim cmd As New OracleCommand("INSERT INTO USER (name, address, photo) VALUES ('User1', '--', :photo)", oracleConnection)
Dim fs As IO.FileStream = New IO.FileStream("c:\img.jpg", IO.FileMode.Open)
Dim br As New IO.BinaryReader(fs)
cmd.Parameters.Add(New OracleParameter("photo", OracleDbType.Blob)).Value = br.ReadBytes(fs.Length)
cmd.ExecuteNonQuery() 'here throws ORA-01008
Изменение значения параметра адреса '-' до '00' или другое. Работает.