sql >> Base de Datos >  >> RDS >> Oracle

cómo obtener, eliminar, confirmar desde el cursor

¿Por qué quieres comprometerte en lotes? Eso solo ralentizará su procesamiento. A menos que haya otras sesiones que estén tratando de modificar las filas que está tratando de eliminar, lo que parece problemático por otras razones, el enfoque más eficiente sería simplemente eliminar los datos con un solo DELETE, es decir,

DELETE FROM uiv_response_income uri
 WHERE EXISTS( 
    SELECT 1
      FROM (<<bulk_delete_dup query>>) bdd
     WHERE bdd.rowid = uri.rowid
  )

Por supuesto, puede haber una forma más óptima de escribir esto dependiendo de cómo esté diseñada la consulta detrás del cursor.

Si realmente desea eliminar BULK COLLECT (lo que ralentizará sustancialmente el proceso), puede usar la sintaxis WHERE CURRENT OF para hacer DELETE

SQL> create table foo
  2  as
  3  select level col1
  4    from dual
  5  connect by level < 10000;

Table created.

SQL> ed
Wrote file afiedt.buf

  1  declare
  2    cursor c1 is select * from foo for update;
  3    l_rowtype c1%rowtype;
  4  begin
  5    open c1;
  6    loop
  7      fetch c1 into l_rowtype;
  8      exit when c1%notfound;
  9      delete from foo where current of c1;
 10    end loop;
 11* end;
SQL> /

PL/SQL procedure successfully completed.

Tenga en cuenta, sin embargo, que dado que tiene que bloquear la fila (con la cláusula FOR UPDATE), no puede poner una confirmación en el ciclo. Hacer una confirmación liberaría los bloqueos que había solicitado con FOR UPDATE y obtendrá un ORA-01002:error de búsqueda fuera de secuencia

SQL> ed
Wrote file afiedt.buf

  1  declare
  2    cursor c1 is select * from foo for update;
  3    l_rowtype c1%rowtype;
  4  begin
  5    open c1;
  6    loop
  7      fetch c1 into l_rowtype;
  8      exit when c1%notfound;
  9      delete from foo where current of c1;
 10      commit;
 11    end loop;
 12* end;
SQL> /
declare
*
ERROR at line 1:
ORA-01002: fetch out of sequence
ORA-06512: at line 7

Es posible que no obtenga un error de tiempo de ejecución si elimina el bloqueo y evita la sintaxis WHERE CURRENT OF, eliminando los datos en función de los valores que obtuvo del cursor. Sin embargo, esto todavía está haciendo una búsqueda a través del compromiso, lo cual es una mala práctica y aumenta radicalmente las probabilidades de que, al menos de forma intermitente, obtenga un error ORA-01555:instantánea demasiado antigua. También será terriblemente lento en comparación con la instrucción SQL única o la opción BULK COLLECT.

SQL> ed
Wrote file afiedt.buf

  1  declare
  2    cursor c1 is select * from foo;
  3    l_rowtype c1%rowtype;
  4  begin
  5    open c1;
  6    loop
  7      fetch c1 into l_rowtype;
  8      exit when c1%notfound;
  9      delete from foo where col1 = l_rowtype.col1;
 10      commit;
 11    end loop;
 12* end;
SQL> /

PL/SQL procedure successfully completed.

Por supuesto, también debe asegurarse de que su proceso se pueda reiniciar en caso de que procese algún subconjunto de filas y tenga un número desconocido de confirmaciones provisionales antes de que el proceso muera. Si el DELETE es suficiente para que la fila ya no se devuelva desde el cursor, es probable que el proceso ya se pueda reiniciar. Pero, en general, eso es una preocupación si intenta dividir una sola operación en varias transacciones.