Как найти количество записей в курсоре Oracle PL/SQL?

вот мой курсор:

CURSOR C1 IS SELECT * FROM MY_TABLE WHERE SALARY < 50000 FOR UPDATE;

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

Я хочу вызвать ошибку приложения в том случае, если в моем курсоре есть

каков наилучший шаблон для этого случая использования? Нужно ли создавать фиктивную переменную MY_TABLE%ROWTYPE, а затем цикл через курсор, чтобы вытащить их и вести счет, или есть более простой способ? Если это способ сделать, будет ли извлечение всех строк в моем курсоре неявно закрывать его, тем самым открывая эти строки, или он останется открытым, пока я явно не закрою его, даже если я извлек их все?

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

5 ответов


NB: я только что перечитал ваш вопрос.. и вы хотите потерпеть неудачу, если есть только 1 запись.. я опубликую новое обновление через минуту..

давайте начнем здесь..

С руководство и справочник пользователя Oracle® Database PL/SQL Выпуск 10г 2 (10.2) Номер Детали B14261-01 ссылка

все строки блокируются при открытии курсора, а не при их извлечении. Строки разблокируются при фиксации или откате транзакции. Поскольку строки больше не заблокированы, вы не можете извлечь из курсора FOR UPDATE после фиксации.

так что вам не нужно беспокоиться о разблокирование записей.

так что попробуйте эту..

declare 
  CURSOR mytable_cur IS SELECT * FROM MY_TABLE WHERE SALARY < 50000 FOR UPDATE;

  TYPE mytable_tt IS TABLE OF mytable_cur %ROWTYPE
    INDEX BY PLS_INTEGER;

  l_my_table_recs mytable_tt;
  l_totalcount NUMBER;
begin

   OPEN mytable_cur ;
   l_totalcount := 0;

   LOOP
      FETCH mytable_cur 
      BULK COLLECT INTO l_my_table_recs LIMIT 100;

      l_totalcount := l_totalcount + NVL(l_my_table_recs.COUNT,0);

      --this is the check for only 1 row..
      EXIT WHEN l_totalcount < 2;

      FOR indx IN 1 .. l_my_table_recs.COUNT
      LOOP
         --process each record.. via l_my_table_recs (indx)

      END LOOP;

      EXIT WHEN mytable_cur%NOTFOUND;
   END LOOP;

   CLOSE mytable_cur ;
end;

АЛЬТЕРНАТИВНЫЙ ОТВЕТ Я прочитал вам ответ назад, чтобы начать, и подумал, что вы хотите выйти, если было больше 1 строки.. не совсем так.. так вот мой предыдущий ответ.

2 простых способа проверить только 1 запись.

Вариант 1-Явные Fetchs

declare 
  CURSOR C1 IS SELECT * FROM MY_TABLE WHERE SALARY < 50000 FOR UPDATE;
  l_my_table_rec C1%rowtype;
  l_my_table_rec2 C1%rowtype;
begin

    open C1;
    fetch c1 into l_my_table_rec;

    if c1%NOTFOUND then
       --no data found
    end if;

    fetch c1 into l_my_table_rec2;
    if c1%FOUND THEN
      --i have more then 1 row
    end if;
    close c1;

  -- processing logic

end;

надеюсь, вы поняли.

Вариант 2 - Исключение Ловли

declare 
  CURSOR C1 IS SELECT * FROM MY_TABLE WHERE SALARY < 50000 FOR UPDATE;
  l_my_table_rec C1%rowtype;
begin
  begin
    select * 
      from my_table
      into l_my_table_rec
     where salary < 50000
       for update;
  exception
    when too_many_rows then
      -- handle the exception where more than one row is returned
    when no_data_found then
      -- handle the exception where no rows are returned
    when others then raise;
  end;

  -- processing logic
end;

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

это особенно полезно, когда у вас вступит в запросе.

кроме того, rememebr вы можете обновить строки в таблице с

UPDATE table_name
SET set_clause
WHERE CURRENT OF cursor_name;

введите оператор, но я буду работать, только если вы не "извлекли" 2-ю строку..


для получения дополнительной информации о курсоре для циклов.. пытаться здесь


Если вы хотите потерпеть неудачу, когда у вас более 1 строки, попробуйте следующее:

declare 
  l_my_table_rec my_table%rowtype;
begin
  begin
    select * 
      from my_table
      into l_my_table_rec
     where salary < 50000
       for update;
  exception
    when too_many_rows then
      -- handle the exception where more than one row is returned
    when no_data_found then
      -- handle the exception where no rows are returned
    when others then raise;
  end;

  -- processing logic
end;

Если это способ сделать это, будет выборка всех строк курсора неявно закройте его, таким образом открывая эти ряды!--3-->

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

Я бы

declare
  CURSOR C1 IS SELECT * FROM MY_TABLE WHERE SALARY < 50000 FOR UPDATE;;
  v_1 c1%rowtype;
  v_cnt number;
begin
  open c_1;
  select count(*) into v_cnt FROM MY_TABLE WHERE SALARY < 50000 and rownum < 3;
  if v_cnt < 2 then
    raise_application_error(-20001,'...');
  end if;
  --other processing
  close c_1;
end;

есть очень маленький шанс, что между временем открытия курсора (блокировка строк) и количеством выбора кто-то вставить одну или несколько строк в таблицу с зарплатой в 50000. В этом случае будет вызвана ошибка приложения, но курсор будет обрабатывать только строки, присутствующие при открытии курсора. Если это вызывает беспокойство, в конце сделайте еще одну проверку на c_1%rowcount и, если эта проблема возникла, вам нужно будет откатиться к точке сохранения.


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


вы можете начать транзакцию и проверить, если выберите COUNT(*) MY_TABLE, где зарплата