Я выполняю хранимую процедуру 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 Database предоставляет высокоуровневый доступ к данным с помощью инструментов и библиотек, таких как Oracle Application Express (APEX).
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;
Конечно, если это была ошибка, это означает, что на самом деле существует более одного значения, поэтому, вероятно, не имеет смысла в программировании просто выбирать одно случайное значение, подобное этому. Вам придется подумать о том, какой из них вы действительно хотите.
Мне удалось решить эту проблему с помощью администратора базы данных. Похоже, что файл tnsnames.ora был обновлен, и хост был обновлен, чтобы указывать на какой-то другой сервер. Однако имя службы и учетные данные остались такими же, как и раньше, поэтому моя конфигурация SSIS работала должным образом.
По сути, я подключался к другому серверу с такой же структурой. И на этом сервере таблица TEST.STAGE_DATA уже была заполнена некоторыми данными, которые имели дубликаты. Таким образом, ошибка 01422 на самом деле была выдана оператором слияния, поскольку было найдено более 1 записи для условия слияния.
Хотя я в некоторой степени работал с SSIS, я впервые подключаюсь к базе данных Oracle, отсюда и допущенная ошибка. Спасибо всем за ваше время и вклад в это, очень ценю это.