Вот мой курсор:
CURSOR C1 IS SELECT * FROM MY_TABLE WHERE SALARY < 50000 FOR UPDATE;
Я сразу открываю курсор для блокировки этих записей на время моей процедуры.
Я хочу повысить ошибку приложения, если существует <2 записи в моем курсоре. Используя C1%ROWCOUNT перестало работать свойство, потому что это только считает число, которые были выбраны к настоящему времени.
Каков лучший шаблон для этого варианта использования? Я должен создать фиктивную переменную MY_TABLE%ROWTYPE и затем цикл через курсор, чтобы достать их и провести подсчет, или есть ли более простой путь? Если это - способ сделать это, будет выборка всех строк в моем курсоре, неявно закрывают его, таким образом разблокировав те строки, или это останется открытым, пока я явно не закрою его, даже если я выбрал их всех?
Я должен удостовериться, что курсор остается открытым для множества других задач вне этого количества.
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 .. попробуйте Здесь
Если это то, что нужно сделать, будет ли выборка всех строк в моем курсоре неявно закроет его, тем самым разблокировав эти строки
Блокировки будут присутствовать в течение всей транзакции (т.е. пока вы не сделаете коммит или откат) независимо от того, когда (или если) вы закроете курсор.
Я бы выбрал
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 и, если такая проблема возникла, сделайте откат к точке сохранения.
Создайте точку сохранения перед итерацией курсора и затем используйте частичный откат, когда обнаружите, что возвращено < 2 записей.
Если вы хотите потерпеть неудачу, когда вы получили более одной строки, попробуйте следующее:
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;
Я считаю, что эта ошибка может возникнуть, если вы используете одно и то же соединение/курсор из нескольких потоков. Однако я не думаю, что создатели "Джанго" допустили такую ошибку, но если вы делаете что-то сами, это легко может произойти.
-121--3612685- Часть о вызове finalize ()
применяется только к вызовам из GC. Можно представить, что объект имеет скрытый флаг " finalize ()
был вызван GC", и GC проверяет этот флаг, чтобы знать, что делать с объектом. На флаг никак не влияют ваши собственные звонки ручной работы на finalize ()
.
После завершения прочтите эту статью от Ханса Бема (который хорошо известен своей работой по сбору мусора). Это открывало глаза на завершение; в частности, Бем объясняет, почему доработка обязательно асинхронна. Следствием этого является то, что, хотя завершение является мощным инструментом, он очень редко является правильным инструментом для данной работы.
-121--1278242-Можно запустить транзакцию и проверить, не превышает ли значение SELECT COUNT (*) MY_TABLE WHERE SALARY < 50000 1.