Pregunta

Tengo un par de escenarios:

  1. Necesita leer el valor de una columna de tres tablas diferentes en un orden predefinido y solo 1 tabla tendrá los datos

  2. Lea los datos de la tabla1 si los registros están presentes para los criterios dados o lea los datos de la Tabla2 para los criterios dados

En procedimientos almacenados de Oracle

La forma en que se manejan en este momento es obtener primero el recuento de una consulta determinada en una variable, y si el recuento > 0, luego ejecutamos la misma consulta para leer los datos reales que en:

select count(*) from table1 into v_count
if v_count > 0
then
    select data into v_data from table1
end if;

Return v_data

Esto se está haciendo para evitar la excepción no_data_found, de lo contrario necesitaría tres bloques de manejador de excepciones para detectar la excepción no_data_found para cada acceso a la tabla.

Actualmente estoy reimplementando esto con los cursores para tener algo como esto:

cursor C1 is
    select data from table1;
Open C1
Fetch C1 into v_data
if C1%FOUND
then
    Close C1
    Return v_data
End If

Quería averiguar cuál es mejor desde el punto de vista del rendimiento: el que tiene cursores o el que hace una selección en una variable y tiene tres bloques de excepción no_data_found. No quiero usar el proceso de consulta en dos etapas que tenemos actualmente.

¿Fue útil?

Solución

No sé por qué estás tan interesado en evitar la excepción. Lo que está mal con:

begin
    begin
        select data into v_data from table1;
    exception
        when no_data_found then
        begin
            select data into v_data from table2;
        exception
            when no_data_found then
            begin
               select data into v_data from table3;
            exception
                when no_data_found then
                    v_data := null;
            end;
        end;
    end;
    return v_data;
end;

Creo que esto funcionará mejor que su otra solución porque hace el mínimo trabajo posible para lograr el resultado deseado.

Consulte ¿Qué tan malo es ignorar la excepción Oracle DUP_VAL_ON_INDEX? donde yo demostrar que el uso de excepciones funciona mejor que contar para ver si hay datos.

Otros consejos

select count(*) from table1 into v_count
if v_count > 0 then
    select data into v_data from table1;
else
    v_data := null;
end if;
return v_data;

NO es equivalente a

begin
    select data into v_data from table1;
    return v_data;
exception
    when no_data_found then
        return null;
end;

en un entorno multiusuario. En el primer caso, alguien podría actualizar la tabla entre los puntos donde verifica la existencia y cuando lee los datos.

En cuanto al rendimiento, no tengo idea de cuál es mejor, pero sé que la primera opción hace dos cambios de contexto al motor sql y la segunda solo hace un cambio de contexto.

La forma en que maneja el escenario 1 ahora no es buena. No solo está haciendo dos consultas cuando una será suficiente, sino que, como señaló Erik, abre la posibilidad de que los datos cambien entre las dos consultas (a menos que use una transacción de solo lectura o serializable).

Dado que usted dice que en este caso los datos estarán exactamente en una de las tres tablas, ¿qué tal esto?

SELECT data
  INTO v_data FROM
  (SELECT data FROM table1
   UNION ALL
   SELECT data FROM table2
   UNION ALL
   SELECT data FROM table3
  )

Otro "truco" puede evitar escribir múltiples manejadores sin datos:

SELECT MIN(data) INTO v_data FROM table1;
IF v_data IS NOT NULL THEN
   return v_data;
END IF;

SELECT MIN(data) INTO v_data FROM table2;
...etc...

pero realmente no veo ninguna razón que sea mejor que tener tres manejadores de excepciones.

Para su segundo escenario, creo que lo que quiere decir es que puede haber datos en ambas tablas y desea usar los datos de la tabla1 si está presente, de lo contrario, use los datos de la tabla 2. Una vez más, podría hacer esto en una sola consulta:

SELECT data
  INTO v_data FROM
  (SELECT data FROM
    (SELECT 1 sort_key, data FROM table1
     UNION ALL
     SELECT 2 sort_key, data FROM table2
    )
   ORDER BY sort_key ASC
  )
  WHERE ROWNUM = 1

Una versión mejorada de la opción MIN de Dave Costa ...

SELECT COUNT(1), MIN(data) INTO v_rowcount, v_data FROM table2;

Ahora se puede verificar v_rowcount para los valores 0, > 1 (mayor que 1) donde la consulta de selección normal arrojará NO_DATA_FOUND o TOO_MANY_ROWS excepción. Valor " 1 " indicará que existe exactamente una fila y servirá a nuestro propósito.

DECLARE
    A VARCHAR(35);
    B VARCHAR(35);
BEGIN
    WITH t AS
    (SELECT OM_MARCA, MAGAZIA FROM ifsapp.AKER_EFECTE_STOC WHERE (BARCODE = 1000000491009))
    SELECT
    (SELECT OM_MARCA FROM t) OM_MARCA,
    (SELECT MAGAZIA FROM t) MAGAZIA
    INTO A, B
    FROM DUAL;
    IF A IS NULL THEN
       dbms_output.put_line('A este null');
    END IF;
    dbms_output.put_line(A);
    dbms_output.put_line(B);
END;
/

Use la " para fila en el cursor " forma de un bucle y el bucle simplemente no se procesará si no hay datos:

declare cursor
t1Cur is
 select ... from table1;
t2Cur is
 select ... from table2;
t3Cur is
 select ... from table3;
t1Flag boolean FALSE;
t2Flag boolean FALSE;
t3Flag boolean FALSE;
begin
for t1Row in t1Cur loop
  ... processing, set t1Flag = TRUE
end loop;
for t2Row in t2Cur loop
  ... processing, set t2Flag = TRUE
end loop;
for t3Row in t3Cur loop
  ... processing, set t3Flag = TRUE
end loop;
... conditional processing based on flags
end;
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top