Как я могу найти количество записей в Oracle МН курсором / курсором SQL?

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

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

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

Я хочу повысить ошибку приложения, если существует <2 записи в моем курсоре. Используя C1%ROWCOUNT перестало работать свойство, потому что это только считает число, которые были выбраны к настоящему времени.

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

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

8
задан aw crud 18 February 2010 в 21:01
поделиться

5 ответов

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

давайте начнем ..

Из Oracle® Database PL / SQL User's Guide and Reference 10g Release 2 (10.2) Part Number B14261-01 reference

Все строки блокируются, когда вы открываете курсор, а не так, как они извлекаются. Строки разблокируются при фиксации или откате транзакции. Поскольку строки больше не заблокированы, вы не можете выполнять выборку из курсора 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 - Явная выборка

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;

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

это особенно полезно, когда в вашем запросе есть соединения.

Также, помните, что вы можете обновить строки в таблице с помощью оператора типа

UPDATE table_name
SET set_clause
WHERE CURRENT OF cursor_name;

, но я буду работать, только если вы не «выбрали» вторую строку ..


для получения дополнительной информации о курсоре Циклы FOR .. попробуйте Здесь

6
ответ дан 5 December 2019 в 20:16
поделиться

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

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

Я бы выбрал

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;

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

1
ответ дан 5 December 2019 в 20:16
поделиться

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

0
ответ дан 5 December 2019 в 20:16
поделиться

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

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;
1
ответ дан 5 December 2019 в 20:16
поделиться

Я считаю, что эта ошибка может возникнуть, если вы используете одно и то же соединение/курсор из нескольких потоков. Однако я не думаю, что создатели "Джанго" допустили такую ошибку, но если вы делаете что-то сами, это легко может произойти.

-121--3612685-

Часть о вызове finalize () применяется только к вызовам из GC. Можно представить, что объект имеет скрытый флаг " finalize () был вызван GC", и GC проверяет этот флаг, чтобы знать, что делать с объектом. На флаг никак не влияют ваши собственные звонки ручной работы на finalize () .

После завершения прочтите эту статью от Ханса Бема (который хорошо известен своей работой по сбору мусора). Это открывало глаза на завершение; в частности, Бем объясняет, почему доработка обязательно асинхронна. Следствием этого является то, что, хотя завершение является мощным инструментом, он очень редко является правильным инструментом для данной работы.

-121--1278242-

Можно запустить транзакцию и проверить, не превышает ли значение SELECT COUNT (*) MY_TABLE WHERE SALARY < 50000 1.

0
ответ дан 5 December 2019 в 20:16
поделиться
Другие вопросы по тегам:

Похожие вопросы: