Die Beschränkung des in()-Operators ist die Wurzel allen Übels.
Es funktioniert für triviale Fälle, und man kann es mit "automatischer Generierung der vorbereiteten Anweisung" erweitern, aber es hat immer seine Grenzen.
- wenn Sie eine Anweisung mit einer variablen Anzahl von Parametern erstellen, wird bei jedem Aufruf ein Sql-Parse-Overhead erzeugt
- auf vielen Plattformen ist die Anzahl der Parameter des Operators in() begrenzt
- auf allen Plattformen ist die Gesamtgröße des SQL-Textes begrenzt, was das Senden von 2000 Platzhaltern für die in params
- das Senden von Bindungsvariablen von 1000-10k ist nicht möglich, da der JDBC-Treiber an seine Grenzen stößt
Der in()-Ansatz kann für einige Fälle gut genug sein, ist aber nicht raketenfest :)
Die raketensichere Lösung besteht darin, die beliebige Anzahl von Parametern in einem separaten Aufruf zu übergeben (z. B. durch Übergabe einer Gruppe von Parametern) und dann eine Ansicht (oder einen anderen Weg) zu haben, um sie in SQL darzustellen und in Ihren Where-Kriterien zu verwenden.
Eine Brute-Force-Variante finden Sie hier http://tkyte.blogspot.hu/2006/06/varying-in-lists.html
Wenn Sie jedoch PL/SQL verwenden können, kann dieses Chaos ziemlich ordentlich werden.
function getCustomers(in_customerIdList clob) return sys_refcursor is
begin
aux_in_list.parse(in_customerIdList);
open res for
select *
from customer c,
in_list v
where c.customer_id=v.token;
return res;
end;
Dann können Sie eine beliebige Anzahl von durch Komma getrennten Kundennummern als Parameter übergeben und:
- wird keine Verzögerung beim Parsen auftreten, da die SQL für select stabil ist
- keine Komplexität von Pipeline-Funktionen - es ist nur eine einzige Abfrage
- das SQL verwendet eine einfache Verknüpfung anstelle eines IN-Operators, was recht schnell ist
- Schließlich ist es eine gute Faustregel, dass no auf die Datenbank mit einem einfachen Select oder DML zuzugreifen, da es sich um Oracle handelt, das weitaus mehr bietet als MySQL oder ähnliche einfache Datenbank-Engines. PL/SQL ermöglicht es Ihnen, das Speichermodell von Ihrem Anwendungsdomänenmodell auf effektive Weise zu trennen.
Der Trick dabei ist:
- Wir brauchen einen Aufruf, der die lange Zeichenkette annimmt und an einem Ort speichert, an dem die DB-Sitzung darauf zugreifen kann (z. B. eine einfache Paketvariable oder dbms_session.set_context)
- dann brauchen wir eine Ansicht, die diese in Zeilen zerlegen kann
- und dann haben Sie eine Ansicht, die die abgefragten IDs enthält, so dass Sie nur eine einfache Verknüpfung mit der abgefragten Tabelle benötigen.
Die Ansicht sieht so aus:
create or replace view in_list
as
select
trim( substr (txt,
instr (txt, ',', 1, level ) + 1,
instr (txt, ',', 1, level+1)
- instr (txt, ',', 1, level) -1 ) ) as token
from (select ','||aux_in_list.getpayload||',' txt from dual)
connect by level <= length(aux_in_list.getpayload)-length(replace(aux_in_list.getpayload,',',''))+1
wobei aux_in_list.getpayload sich auf die ursprüngliche Eingabezeichenfolge bezieht.
Ein möglicher Ansatz wäre die Übergabe von pl/sql-Arrays (die nur von Oracle unterstützt werden), allerdings können diese nicht in reinem SQL verwendet werden, weshalb immer ein Konvertierungsschritt erforderlich ist. Die Konvertierung kann nicht in SQL erfolgen, so dass die Übergabe eines Clob mit allen Parametern als String und dessen Konvertierung in einer Ansicht die effizienteste Lösung ist.