Oracle - выберите И удалите в процедуре - PullRequest
3 голосов
/ 12 мая 2009

Мне нужно вернуть набор строк из процедуры Oracle, а затем удалить их в той же процедуре. Есть ли аккуратный способ сделать это без временных таблиц? Может быть, что-то вроде курсора в памяти?

По сути, я выталкиваю записи из очереди, и я хочу избежать двухкратных поездок, потому что это очень частый процесс.

Ответы [ 6 ]

8 голосов
/ 12 мая 2009

На самом деле, вы можете сделать это без SELECT в эти дни. Вы можете просто УДАЛИТЬ интересующие вас записи и использовать предложение RETURNING для извлечения этих записей в локальную переменную по мере их удаления.

DELETE FROM my_table
  WHERE <whatever conditions>
  RETURNING column1, column2, ...
  INTO array1, array2, ...

Немного раздражает то, что вам нужно извлекать каждый столбец в отдельную переменную. Вы не можете использовать тип записи в этом контексте. Так что если у вас много столбцов, это может стать громоздким.

3 голосов
/ 12 мая 2009

Вы можете вернуть курсор из процедуры или анонимного блока:

BEGIN
        OPEN :cur FOR
        SELECT  *
        FROM    table
        WHERE   condition;

        DELETE
        FROM    table
        WHERE   condition;

END;

Курсор сохранится после удаления.

См. Запись в моем блоге для подробных объяснений:

, и вот эта запись в двух словах:

CREATE TABLE t_deleter (id INT NOT NULL PRIMARY KEY, value VARCHAR2(50))
/
INSERT
INTO    t_deleter (id, value)
VALUES (1, 'Value 1')
/
INSERT
INTO    t_deleter (id, value)
VALUES (2, 'Value 2')
/
COMMIT
/
SELECT  *
FROM    t_deleter
/
VAR cur REFCURSOR
BEGIN
        OPEN    :cur FOR
        SELECT  *
        FROM    t_deleter
        WHERE   id = 1;
        DELETE
        FROM    t_deleter
        WHERE   id = 1;
END;
/
PRINT cur
SELECT  *
FROM    t_deleter
/

Table created.


1 row created.


1 row created.


Commit complete.


        ID VALUE
---------- --------------------------------------------------
         1 Value 1
         2 Value 2


PL/SQL procedure successfully completed.


/*
   PRINT CUR
   This is what returned to the client
*/

        ID VALUE
---------- --------------------------------------------------
         1 Value 1

/*
   SELECT  *
   FROM    t_deleter

   This is what's left after the procedure completed
*/


        ID VALUE
---------- --------------------------------------------------
         2 Value 2
3 голосов
/ 12 мая 2009

Вы можете использовать курсор для обновления, например,

DECLARE
  CURSOR c_updates
  IS
    SELECT *
    FROM table1 t1
    LEFT JOIN table2 t2 ON t1.field = t2.field
    WHERE t2.field IS NULL
  FOR UPDATE OF t1.field;

  l_record c_updates%ROWTYPE;
BEGIN
  OPEN c_updates;

  LOOP
    FETCH c_updates INTO l_record;
    EXIT WHEN c_updates%NOTFOUND;

    --Do what you want with l_record

    DELETE FROM table1
    WHERE CURRENT OF c_updates;
  END LOOP;

  CLOSE c_updates;
END;
2 голосов
/ 12 мая 2009

Опираясь на ответ Рувимпериса и ответ cagcowboy :

ПРЕДУПРЕЖДЕНИЕ: В настоящий момент у меня нет доступа к компилятору PL / SQL, поэтому есть вероятность, что что-то не так.

TYPE popped_records_table_type IS TABLE OF my_table%ROWTYPE INDEX BY BINARY_INTEGER;

FUNCTION pop_records(...) RETURN popped_records_table_type IS
    popped_records popped_records_table_type;
    popped_record my_table%ROWTYPE;
    next_popped_record_index BINARY_INTEGER;

    CURSOR popped_records_cursor IS
        SELECT * FROM my_table WHERE ... FOR UPDATE;
BEGIN
    next_popped_record_index := 1;

    OPEN popped_records_cursor;

    LOOP
        FETCH popped_records_cursor INTO popped_record;
        EXIT WHEN popped_records_cursor%NOTFOUND;

        DELETE FROM my_table WHERE CURRENT OF popped_records_cursor;

        popped_records(next_popped_record_index) := popped_record;
        next_popped_record_index := next_popped_record_index + 1;
    END LOOP;

    CLOSE popped_records_cursor;

    RETURN popped_records;
END;

Редактировать: я считаю, что это также будет работать с хранимой процедурой, если вы предоставите экземпляр popped_records_table_type в качестве параметра IN / OUT:

PROCEDURE pop_records(popped_records IN OUT popped_records_table_type, ...) IS
    -- Pretty much the same as above
2 голосов
/ 12 мая 2009

Заполнить данные в ТИП и вернуть это?

, например

CREATE TYPE blah as (data-columns-go-here)
/

CREATE TYPE blah_table AS TABLE OF blah;
/
0 голосов
/ 12 мая 2009

В Oracle есть что-то, что называется расширенной очередью, может быть, лучше использовать эту функцию, чем создавать собственную систему очередей.

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