Переменная, содержащая количество строк, затронутых предыдущим DELETE? (в функции)

У меня есть функция, которая используется как триггер INSERT. Эта функция удаляет строки, которые конфликтуют с [серийным номером в] вставляемой строкой. Он работает красиво, поэтому я бы предпочел не обсуждать достоинства концепции.

DECLARE
re1 feeds_item.shareurl%TYPE;
BEGIN
SELECT regexp_replace(NEW.shareurl, '/[^/]+(-[0-9]+\.html)$','/[^/]+\\1') INTO re1;
RAISE NOTICE 'DELETEing rows from feeds_item where shareurl ~ ''%''', re1;

DELETE FROM feeds_item where shareurl ~ re1;
RETURN NEW;
END;

Я хотел бы добавить в УВЕДОМЛЕНИЕ указание того, сколько строк затронуто (aka: deleted). Как я могу это сделать (используя LANGUAGE 'plpgsql')?

UPDATE: Основываясь на отличном руководстве от "Курица на кухне", я изменил его на это:

DECLARE
re1 feeds_item.shareurl%TYPE;
num_rows int;
BEGIN
SELECT regexp_replace(NEW.shareurl, '/[^/]+(-[0-9]+\.html)$','/[^/]+\\1') INTO re1;

DELETE FROM feeds_item where shareurl ~ re1;
IF FOUND THEN
    GET DIAGNOSTICS num_rows = ROW_COUNT;
    RAISE NOTICE 'DELETEd % row(s) from feeds_item where shareurl ~ ''%''', num_rows, re1;
END IF;
RETURN NEW;
END;

Ответы

Ответ 1

В Oracle PL/SQL системная переменная для хранения числа удаленных/вставленных/обновленных строк:

SQL%ROWCOUNT

После инструкции DELETE/INSERT/UPDATE и ПЕРЕД ОБЕСПЕЧЕНИЕМ вы можете сохранить SQL% ROWCOUNT в переменной типа NUMBER. Помните, что COMMIT или ROLLBACK reset для ZERO значение SQL% ROWCOUNT, поэтому вам нужно скопировать значение SQL% ROWCOUNT в переменную BEFORE COMMIT или ROLLBACK.

Пример:

BEGIN
   DECLARE
      affected_rows   NUMBER DEFAULT 0;
   BEGIN
      DELETE FROM feeds_item
            WHERE shareurl = re1;

      affected_rows := SQL%ROWCOUNT;
      DBMS_OUTPUT.
       put_line (
            'This DELETE would affect '
         || affected_rows
         || ' records in FEEDS_ITEM table.');
      ROLLBACK;
   END;
END;

Я нашел также это интересное решение (источник: http://markmail.org/message/grqap2pncqd6w3sp)

7/7/07, Karthikeyan Sundaram написал:

Привет,

I am using 8.1.0 postgres and trying to write a plpgsql block.  In that I am inserting a row.  I want to check to see if the row has been

вставлен или нет.

В оракуле мы можем так сказать

begin
  insert into table_a values (1);
  if sql%rowcount > 0
  then
    dbms.output.put_line('rows inserted');
  else
    dbms.output.put_line('rows not inserted');
 end if;  end;

Есть ли что-то равное sql% rowcount в postgres? Пожалуйста, помогите.

С уважением, skarthi

Может быть:

http://www.postgresql.org/docs/8.2/static/plpgsql-statements.html#PLPGSQL-STATEMENTS-SQL-ONEROW

Нажмите на ссылку выше, вы увидите следующее:

37.6.6. Получение статуса результата Существует несколько способов определения эффекта команды. Первый способ - использовать GET DIAGNOSTICS, которая имеет следующую форму:

GET DIAGNOSTICS variable = item [,...]; Эта команда позволяет извлечение индикаторов состояния системы. Каждый элемент является ключевым словом определение значения состояния, которое должно быть присвоено указанной переменной (который должен иметь правильный тип данных для его получения). В настоящее время доступными элементами состояния являются ROW_COUNT, количество строк, обработанных последняя команда SQL, отправленная в SQL-механизм, и RESULT_OID, OID последней строки, вставленной последней командой SQL. Обратите внимание, что RESULT_OID полезен только после команды INSERT в таблицу содержащих OID.

Пример:

GET DIAGNOSTICS integer_var = ROW_COUNT; Второй способ определить влияние команды - проверить специальную переменную названный FOUND, который имеет тип boolean. FOUND начинает ложь внутри каждый вызов функции PL/pgSQL. Он устанавливается каждым из следующих типов утверждений:

Оператор SELECT INTO устанавливает FOUND true, если строка назначена, false, если строка не возвращается.

Оператор PERFORM устанавливает FOUND true, если он производит (и отбрасывает) a строка, false, если строка не создается.

Условные обозначения UPDATE, INSERT и DELETE установлены на FOUND true, если хотя бы один строка влияет, false, если ни одна строка не затронута.

Оператор FETCH устанавливает FOUND true, если он возвращает строку, false, если нет строки возвращается.

Оператор FOR устанавливает FOUND true, если он выполняет итерацию один или несколько раз, иначе ложный. Это относится ко всем трем вариантам выражения FOR (целые циклы FOR, набор записей для циклов FOR и динамический набор записей FOR петли). FOUND устанавливается таким образом, когда цикл FOR завершает работу; внутри выполнение цикла, FOUND не модифицируется оператором FOR, хотя он может быть изменен путем выполнения других заявлений внутри тело петли.

FOUND - локальная переменная в каждой функции PL/pgSQL; любые изменения это влияет только на текущую функцию.

Ответ 2

Для очень надежного решения, которое является частью PostgreSQL SQL, а не только plpgsql, вы также можете сделать следующее:

with a as (DELETE FROM feeds_item WHERE shareurl ~ re1 returning 1)
select count(*) from a;

Вы можете получить гораздо больше информации, например:

with a as (delete from sales returning amount)
select sum(amount) from a;

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

Ответ 3

Я хотел бы поделиться своим кодом (у меня была эта идея от Roelof Rossouw):

CREATE OR REPLACE FUNCTION my_schema.sp_delete_mytable(_id integer)
  RETURNS integer AS
$BODY$
  DECLARE
    AFFECTEDROWS integer;
  BEGIN
    WITH a AS (DELETE FROM mytable WHERE id = _id RETURNING 1)
    SELECT count(*) INTO AFFECTEDROWS FROM a;
    IF AFFECTEDROWS = 1 THEN
      RETURN 1;
    ELSE
      RETURN 0;
    END IF;
  EXCEPTION WHEN OTHERS THEN
    RETURN 0;
  END;
$BODY$
  LANGUAGE plpgsql VOLATILE
  COST 100;