Ошибка ORA-01422, возникающая при выполнении хранимой процедуры из задачи сценария SSIS, однако она выполняется успешно при запуске из SQL Developer

Я выполняю хранимую процедуру 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).


58
2

Ответы:

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, отсюда и допущенная ошибка. Спасибо всем за ваше время и вклад в это, очень ценю это.