Я выполняю хранимую процедуру Oracle из задачи сценария SSIS, и пакет используется для успешного выполнения без каких-либо проблем. Однако внезапно он начал давать сбой из-за ошибки ORA-01422.
Не было никаких изменений пакетов, изменений хранимых процедур или изменений конфигурации, из которой извлекается соединение.
Кроме того, SELECT INTO
, который у меня есть на стороне Oracle в хранимой процедуре, просто выполняет SELECT COUNT(1) INTO
- поэтому я не совсем уверен, как он может получить более 1 строки, что, насколько я понимаю, предполагает ошибка.
Кроме того, хранимая процедура успешно запускается при выполнении вручную из Oracle SQL Developer, что меня сбивает с толку.
Я работаю в основном с T-SQL и SSIS, поэтому не уверен, что что-то упускаю при попытке прочитать ошибку PL/SQL.
Обновлено:
Это мой код задачи скрипта:
OracleConnection OracleConn = new OracleConnection(Dts.Variables["OracleConnectionString"].Value.ToString());
OracleCommand OracleCmd = new OracleCommand("TEST.TEST_DATA", OracleConn);
OracleCmd.CommandType = CommandType.StoredProcedure;
OracleParameter ins_count = new OracleParameter("ins_count", OracleDbType.Int32);
ins_count.Direction = ParameterDirection.Output;
OracleCmd.Parameters.Add(ins_count);
OracleParameter upd_count = new OracleParameter("upd_count", OracleDbType.Int32);
upd_count.Direction = ParameterDirection.Output;
OracleCmd.Parameters.Add(upd_count);
OracleParameter rev_count = new OracleParameter("rev_count", OracleDbType.Int32);
rev_count.Direction = ParameterDirection.Output;
OracleCmd.Parameters.Add(rev_count);
OracleConn.Open();
OracleCmd.ExecuteNonQuery();
string returnValue = ins_count.Value.ToString();
Dts.Variables["DestInsCount"].Value = Convert.ToInt64(returnValue);
returnValue = upd_count.Value.ToString();
Dts.Variables["DestUpdCount"].Value = Convert.ToInt64(returnValue);
returnValue = rev_count.Value.ToString();
Dts.Variables["DestRevCount"].Value = Convert.ToInt64(returnValue);
Я получаю ошибку в ExecuteNonQuery. ORA-01422: точная выборка возвращает больше строк, чем запрошено\nORA-06512: в "TEST.TEST_DATA"
Вот код хранимой процедуры Oracle:
CREATE PROCEDURE TEST_DATA
(
ins_count OUT number,
upd_count OUT number,
rev_count OUT number
)
AS
log_id_v number;
update_cnt number;
insert_cnt number;
reverse_cnt number;
stg_cnt number;
BEGIN
SELECT COUNT(1) INTO stg_cnt
FROM TEST.STAGE_DATA;
IF (stg_cnt > 0) THEN
--Records exist in the stage table
INSERT INTO TEST.DATA
(
DATE,
CLIENT_ID,
PROGRAM_ID,
STATUS,
LOG_ID
)
SELECT
TD.DATE,
TD.CLIENT_ID,
TD.PROGRAM_ID,
TD.STATUS,
STD.LOG_ID
FROM TEST.DATA TD
INNER JOIN TEST.STAGE_DATA STD
ON TD.DATE = STD.DATE
AND TD.CLIENT_ID = STD.CLIENT_ID
AND TD.PROGRAM_ID = STD.PROGRAM_ID
AND TD.STATUS <> 'Reverse'
WHERE TD.MODIFIED_DTM = (
SELECT MAX(TD.MODIFIED_DTM)
FROM TEST.DATA TD
WHERE TD.CLIENT_ID = STD.CLIENT_ID
AND TD.PROGRAM_ID = STD.PROGRAM_ID
AND TD.DATE = STD.DATE
AND TD.STATUS <> 'Reverse'
);
--Get current LOG_ID - stage table should have only one
SELECT DISTINCT(LOG_ID) INTO log_id_v
FROM TEST.STAGE_DATA;
--Get count of records inserted with reverse status in main table
SELECT COUNT(1) INTO reverse_cnt
FROM TEST.DATA
WHERE STATUS = 'Reverse'
AND LOG_ID = log_id_v;
INSERT INTO TEST.DATA
(
DATE,
CLIENT_ID,
PROGRAM_ID,
STATUS,
LOG_ID
)
SELECT
SELECT
STD.DATE,
STD.CLIENT_ID,
STD.PROGRAM_ID,
'Update',
STD.LOG_ID
FROM TEST.STAGE_DATA STD
WHERE EXISTS
(
SELECT 1
FROM TEST.DATA TD
WHERE TD.CLIENT_ID = STD.CLIENT_ID
AND TD.PROGRAM_ID = STD.PROGRAM_ID
AND TD.DATE = STD.DATE
AND TD.STATUS <> 'Reverse'
);
--Get count of records inserted with update status in main table
SELECT COUNT(1) INTO update_cnt
FROM TEST.DATA
WHERE STATUS = 'Update'
AND LOG_ID = log_id_v;
--Insert new records
MERGE INTO TEST.DATA TD
USING TEST.STAGE_DATA STD
ON (
TD.CLIENT_ID = STD.CLIENT_ID
AND TD.PROGRAM_ID = STD.PROGRAM_ID
AND TD.DATE = STD.DATE
)
WHEN NOT MATCHED THEN INSERT
(
DATE,
CLIENT_ID,
PROGRAM_ID,
STATUS,
LOG_ID
)
VALUES
(
STD.DATE,
STD.CLIENT_ID,
STD.PROGRAM_ID,
'New',
STD.LOG_ID
);
--Get count of records inserted with new status in main table
SELECT COUNT(1) INTO insert_cnt
FROM TEST.DATA
WHERE STATUS = 'New'
AND LOG_ID = log_id_v;
--Set output variables
rev_count := reverse_cnt;
ins_count := insert_cnt;
upd_count := update_cnt;
ELSE
--when no records in stage table
--Set output variables to 0
ins_count := 0;
upd_count := 0;
rev_count := 0;
END IF;
END;
Обратите внимание, что моя таблица этапов пуста, поэтому код переходит прямо к блоку ELSE и возвращает 0 для всех выходных параметров при запуске вручную из Oracle SQL Developer. Я ожидал такого же результата от своей задачи сценария, но он выдает ошибку ORA, упомянутую выше.
Я не понимаю, как вы ожидаете от нас помощи с кодом, который мы не видим?
Я добавил код, с которым работаю. Дает ли это какую-либо подсказку?
Настоящая проблема здесь в том, что у вас нет номера строки, который точно указывает, где происходит ошибка. По умолчанию исключения Oracle включают стек ошибок и все соответствующие номера строк. Если у вас нет этой информации, код может включать неправильную обработку исключений, которая делает что-то вроде exception when others then dbms_output.put_line(sqlerrm);
Если вы удалите всю пользовательскую обработку исключений, значения по умолчанию, скорее всего, вернут всю необходимую вам отладочную информацию.
SELECT DISTINCT(LOG_ID) INTO log_id_v
FROM TEST.STAGE_DATA;
Это вполне может вернуть более одной строки, что приведет к получению ошибки. Вы не можете использовать неявный курсор в такой переменной, если она не является скаляром (одна строка). Я предлагаю использовать агрегат типа MAX
:
SELECT MAX(LOG_ID) INTO log_id_v
FROM TEST.STAGE_DATA;
Конечно, если это была ошибка, это означает, что на самом деле существует более одного значения, поэтому, вероятно, не имеет смысла в программировании просто выбирать одно случайное значение, подобное этому. Вам придется подумать о том, какой из них вы действительно хотите.
Спасибо за ваше время. Пытаясь устранить эту ошибку, я усек таблицу TEST.STAGE_DATA, но по-прежнему получаю ту же ошибку. Когда я запускаю хранимую процедуру вручную, код переходит к блоку ELSE из-за условия IF (stg_cnt > 0), а затем устанавливает выходные параметры. Однако запуск хранимой процедуры из задачи сценария SSIS приводит к ошибке ORA 01422.
Мне удалось решить эту проблему с помощью администратора базы данных. Похоже, что файл tnsnames.ora был обновлен, и хост был обновлен, чтобы указывать на какой-то другой сервер. Однако имя службы и учетные данные остались такими же, как и раньше, поэтому моя конфигурация SSIS работала должным образом.
По сути, я подключался к другому серверу с такой же структурой. И на этом сервере таблица TEST.STAGE_DATA уже была заполнена некоторыми данными, которые имели дубликаты. Таким образом, ошибка 01422 на самом деле была выдана оператором слияния, поскольку было найдено более 1 записи для условия слияния.
Хотя я в некоторой степени работал с SSIS, я впервые подключаюсь к базе данных Oracle, отсюда и допущенная ошибка. Спасибо всем за ваше время и вклад в это, очень ценю это.
Вы не показали ни одного своего кода и не показали, почему, по вашему мнению, именно вызов вашей процедуры вызывает ошибку или почему именно этот запрос внутри этой процедуры. Возможно, стек ошибок, который вы видите, действительно указывает на это, но вы этого тоже не показали. Возможно, это другой вызов или другая линия, или вы не подключены к той БД/схеме, о которой думаете, или... кто знает. Вы действительно не дали нам ничего, с чем можно было бы работать.