Domanda

Ho un paio di scenari:

  1. È necessario leggere il valore di una colonna da tre diverse tabelle in un ordine predefinito e solo 1 tabella avrà i dati

  2. Leggi i dati dalla tabella1 se sono presenti record per i criteri forniti altrimenti leggi i dati dalla tabella 2 per i criteri indicati

In Oracle Stored Procedures

Il modo in cui questi vengono gestiti in questo momento è innanzitutto ottenere il conteggio per una determinata query in una variabile e se il conteggio > 0, quindi eseguiamo la stessa query per leggere i dati effettivi come in:

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

Return v_data

Questo viene fatto per evitare l'eccezione no_data_found, altrimenti avrei bisogno di tre blocchi del gestore eccezioni per catturare l'eccezione no_data_found per ogni accesso alla tabella.

Attualmente sto reimplementando questo con i cursori in modo da avere qualcosa del genere:

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

Volevo scoprire quale è meglio dal punto di vista delle prestazioni: quello con i cursori o quello che fa una selezione in una variabile e ha tre blocchi di eccezioni no_data_found. Non voglio utilizzare il processo di query in due fasi che abbiamo attualmente.

È stato utile?

Soluzione

Non so perché sei così desideroso di evitare l'eccezione? Cosa c'è di sbagliato in:

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;

Credo che questo funzionerà meglio dell'altra soluzione perché fa il minimo lavoro possibile per ottenere il risultato desiderato.

Vedi Quanto è grave ignorare l'eccezione Oracle DUP_VAL_ON_INDEX? dove I dimostrare che l'utilizzo delle eccezioni funziona meglio del conteggio per vedere se ci sono dati.

Altri suggerimenti

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;

NON è equivalente a

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

in un ambiente multiutente. Nel primo caso, qualcuno potrebbe aggiornare la tabella tra i punti in cui si verifica l'esistenza e quando si leggono i dati.

Dal punto di vista delle prestazioni, non ho idea di quale sia il migliore, ma so che la prima opzione fa due cambi di contesto al motore sql e il secondo fa solo un cambio di contesto.

Il modo in cui stai gestendo lo scenario 1 ora non è buono. Non solo stai eseguendo due query quando una sarà sufficiente, ma come ha sottolineato Erik, si apre la possibilità di cambiare i dati tra le due query (a meno che non si utilizzi una transazione di sola lettura o serializzabile).

Dato che dici che in questo caso i dati saranno esattamente in una delle tre tabelle, che ne dici di questo?

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

Un altro "trucco" puoi usare per evitare di scrivere più gestori senza dati trovati:

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...

ma non vedo davvero alcun motivo che sia meglio che avere tre gestori di eccezioni.

Per il tuo secondo scenario, penso che intendi dire che potrebbero esserci dei dati in entrambe le tabelle e che vuoi usare i dati della tabella1 se presenti, altrimenti usa i dati della tabella 2. Ancora una volta potresti farlo in un singolo query:

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 versione migliorata dell'opzione MIN di "Dave Costa" ...

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

Ora v_rowcount può essere verificato per i valori 0, > 1 (maggiore di 1) in cui la query di selezione normale genererà NO_DATA_FOUND o TOO_MANY_ROWS eccezione. Valore "1" indicherà che esiste una riga esatta e servirà al nostro scopo.

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;
/

Utilizza " per riga nel cursore " forma di un ciclo e il ciclo non verrà elaborato se non ci sono dati:

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;
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top