Вставка в таблицу с использованием процедуры, только если запись еще не существует - PullRequest
0 голосов
/ 20 октября 2018

У меня есть таблица, которую я пытаюсь заполнить с помощью сценария plsql (работает на разработчику plsql).Фактический оператор DML содержится в процедуре внутри пакета.Процедура вставляется только если запись еще не существует.

Не работает.Часть, которая проверяет существование, возвращает true после первой итерации цикла скрипта, даже если она на самом деле не существует в таблице.

Если я помещу коммит за пределы цикла, ничего не будет вставлено вообще ипроверки существования возвращают true для всех итераций, даже если таблица пуста.

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

Пожалуйста, скажите мне, что я делаю здесь не так.

CREATE OR REPLACE PACKAGE BODY some_package
IS
  PROCEDURE add_to_queue(id IN NUMBER)
  IS
    pending_record VARCHAR2(1);
  BEGIN
    -- this part succeeds even if nothing matches the criteria
    -- during the loop in the outside script
    SELECT 'Y'
    INTO pending_record
    FROM dual
    WHERE EXISTS (SELECT 'x' FROM some_queue smq
                  WHERE smq.id = id AND smq.status IS NULL);
  EXCEPTION
    WHEN NO_DATA_FOUND THEN
      INSERT INTO some_queue (seqno, id, activity_date)
      VALUES (some_sequence.nextval, id, SYSDATE);
    WHEN OTHERS THEN
      NULL;
  END;
END some_package;

CREATE TABLE some_queue
(
  seqno             VARCHAR2(500) NOT NULL,
  id                NUMBER NOT NULL,
  activity_date     DATE NOT NULL,
  status            VARCHAR2(25),
  CONSTRAINT some_queue_pk PRIMARY KEY (seqno)
);

-- script to randomly fill in the table with ids from another table
declare
  type ids_coll_tt is table of number index by pls_integer;

  ids_coll_table ids_coll_tt;

  cursor ids_coll_cur is
    select tab.id
    from (select *
          from ids_source_table
          order by dbms_random.value ) tab
    where rownum < 10;
begin
  open ids_coll_cur;
  fetch ids_coll_cur bulk collect into ids_coll_table;
  close ids_coll_cur;

  for x in 1..ids_coll_table.count
  loop
    some_package.add_to_queue(ids_coll_table(x));
    commit; -- if this is here, the first iteration gets inserted
  end loop;
  -- commit; -- if the commit is done here, nothing gets inserted
end;

Примечание: я перевел этот код, чтобы сделать его более общим для публикации.Извините, если есть какие-либо опечатки.

Обновление: даже если я помещаю все в сценарий и не использую пакет, я не могу должным образом проверить наличие и получаю те же результаты.

Ответы [ 2 ]

0 голосов
/ 20 октября 2018

Не называйте параметр так же, как столбец (используйте префикс, например p_ или in_), и вы можете сделать это в одном операторе, если используете оператор MERGE, самосоединяющийся с ROWID псевдостолбец:

CREATE OR REPLACE PACKAGE BODY some_package
IS
  PROCEDURE add_to_queue(
    in_id IN NUMBER
  )
  IS
  BEGIN
    MERGE INTO some_queue dst
    USING ( SELECT ROWID AS rid
            FROM   some_queue
            WHERE  id = in_id
            AND    status IS NULL ) src
    ON ( src.rid = dst.ROWID )
    WHEN NOT MATCHED THEN
      INSERT (seqno,                 id,    activity_date)
      VALUES (some_sequence.nextval, in_id, SYSDATE);
  END;
END some_package;
0 голосов
/ 20 октября 2018

Я разобрался с решением:

CREATE OR REPLACE PACKAGE BODY some_package
IS
  PROCEDURE add_to_queue(p_id IN NUMBER)
  IS
    pending_record VARCHAR2(1);
  BEGIN
    -- this part succeeds even if nothing matches the criteria
    -- during the loop in the outside script
    SELECT 'Y'
    INTO pending_record
    FROM dual
    WHERE EXISTS (SELECT 'x' FROM some_queue smq
                  WHERE smq.id = p_id AND smq.status IS NULL);
  EXCEPTION
    WHEN NO_DATA_FOUND THEN
      INSERT INTO some_queue (seqno, id, activity_date)
      VALUES (some_sequence.nextval, p_id, SYSDATE);
    WHEN OTHERS THEN
      NULL;
  END;
END some_package;

изменение имени параметра исправило его.Я предполагаю, что компилятор запутается, если его имя совпадает с именем поля таблицы.

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