Oracle Ref Cursor Vs Wählen Sie in mit Ausnahmebehandlung
Frage
Ich habe ein paar Szenarien:
-
Sie benötigen den Wert einer Spalte aus drei verschiedenen Tabellen in einer vorgegebenen Reihenfolge und nur 1 Tabelle lesen wird die Daten haben
-
Daten aus table1 Lesen, wenn Datensätze nach Kriterien vorhanden sind gegeben andere Daten aus Tabelle 2 zu lesen für bestimmte Kriterien
In Oracle Stored Procedures
Die Art, wie diese jetzt behandelt werden, ist zuerst die Zählung für eine bestimmte Abfrage in eine Variable zu erhalten, und wenn die Zählung> 0, dann führen wir die gleiche Abfrage die aktuellen Daten wie in zu lesen:
select count(*) from table1 into v_count
if v_count > 0
then
select data into v_data from table1
end if;
Return v_data
Dies wird getan, die NO_DATA_FOUND Ausnahme zu vermeiden, sonst würde ich drei Ausnahmebehandlungsblocks muß die NO_DATA_FOUND Ausnahme für jede Tabelle Zugang zu fangen.
Zur Zeit ich dies Neuimplementierung mit Cursorn so, dass ich so etwas wie diese:
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
Ich wollte herausfinden, was man von einer Performance-Sicht besser ist - die eine mit Cursorn, oder eine, die eine Auswahl in eine Variable tut und hat drei NO_DATA_FOUND Ausnahmeblocks. Ich will nicht den zweistufige Abfrageprozess verwenden, die wir derzeit haben.
Lösung
Ich weiß nicht, warum du so scharf sind die Ausnahme zu vermeiden? Was ist falsch an:
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;
Ich glaube, dies besser abschneiden wird als die andere Lösung, weil sie die minimal möglichen funktionierts das gewünschte Ergebnis zu erzielen.
Siehe Wie schlimm ignoriert Ausnahme Oracle DUP_VAL_ON_INDEX? , wo ich zeigen, dass Ausnahmen eine bessere Leistung als das Zählen zu sehen, ob es irgendwelche Daten.
mitAndere Tipps
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;
ist nicht gleichbedeutend mit
begin
select data into v_data from table1;
return v_data;
exception
when no_data_found then
return null;
end;
in einer Mehrbenutzerumgebung. Im ersten Fall, jemand in der Tabelle zwischen den Punkten aktualisieren konnte, wo man auf die Existenz überprüfen und wenn Sie die Daten gelesen werden.
Performance-weise, habe ich keine Ahnung was besser ist, aber ich weiß, dass die erste Option zwei Zusammenhang auf den SQL-Engine schaltet macht und die zweiten nur, dass ein Kontext-Switch.
Wie Sie Szenario 1 jetzt Handhabung sind nicht gut. Nicht nur tun Sie zwei Abfragen, wenn man ausreichen, aber wie Erik wies darauf hin, es eröffnet sich die Möglichkeit der Daten Wechsel zwischen den beiden Abfragen (es sei denn, Sie eine schreibgeschützte oder serializable Transaktion verwenden).
Da Sie in diesem Fall sagen, dass die Daten in genau eine der drei Tabellen sein, wie etwa das?
SELECT data
INTO v_data FROM
(SELECT data FROM table1
UNION ALL
SELECT data FROM table2
UNION ALL
SELECT data FROM table3
)
Ein weiterer „Trick“ Sie können keine-Daten-Handler gefunden verwenden, um Schreiben mehr zu vermeiden wären:
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...
, aber ich sehe nicht wirklich einen Grund, die besser ist als mit drei Ausnahmebehandler.
Für Ihr zweites Szenario, denke ich, was Sie meinen, dass es Daten in beiden Tabellen sein kann, und Sie mögen die Daten von Tabelle 1 verwenden, wenn vorhanden, andernfalls die Daten aus der Tabelle verwendet 2. Wieder Sie dies in einem einzigen tun könnte Abfrage:
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
Eine erweiterte Version von "Dave Costa" 's MIN Option ...
SELECT COUNT(1), MIN(data) INTO v_rowcount, v_data FROM table2;
Jetzt kann v_rowcount
für Werte 0,> 1 (größer als 1), wo normale Auswahlabfrage NO_DATA_FOUND
oder TOO_MANY_ROWS
Ausnahme werfen wird geprüft werden. Wert „1“ zeigt an, dass genau eine Zeile vorhanden ist, und wird unseren Zweck dienen.
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;
/
Verwenden der „für die Zeile in cursor“ Form einer Schleife, und die Schleife wird verarbeiten einfach nicht, wenn es keine Daten:
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;