Dass Oracle regelmäßig darauf hinweist, dass man vom Datentyp LONG Abstand nehmen sollte, ist bekannt. Und bekannt ist auch, dass im data dictionary auch in aktuellen Releases (hier 11.1.0.7) immer noch eine ganze Reihe von LONG-Spalten zu finden ist:
select owner , count(*) cnt from dba_tab_columns where data_type = 'LONG' group by owner order by count(*) desc OWNER CNT ------------------------------ ---------- SYS 229 SYSTEM 12
Ich hatte an dieser Stelle gelegentlich schon mal auf Adrian Billingtons umfassende Erläuterung der Möglichkeiten, mit LONGs fertig zu werden, hingewiesen - und darin findet man neben diversen PL/SQL-Optionen auch eine reine SQL-Variante zum Auslesen der LONGs, die mit dem DBMS_XMLGEN-Package operiert. Als ich dieser Tage ein Script basteln wollte, mit dem ich prüfen kann, ob es in einer Datenbank partitionierte Tabellen gibt, die Bewegungsdaten bereits in eine MAXVALUE-Partition schreiben, habe ich damit experimentiert:
-- Anlage einer partitionierten Tabelle -- im gegebenen Fall ist die Tabelle interval partitioned, -- was die Frage nach der MAXVALUE-Partition natürlich hinfällig macht, -- aber das ist für den Test unerheblich create table test_partition_high_value partition by range (id) interval (1) (partition test_p1 values less than (1)) as select rownum id from dual connect by level <= 3; select table_name , partition_name , high_value from user_tab_partitions where table_name = 'TEST_PARTITION_HIGH_VALUE'; TABLE_NAME PARTITION_NAME HIGH_VALUE ------------------------------ ------------------------------ ---------- TEST_PARTITION_HIGH_VALUE TEST_P1 1 TEST_PARTITION_HIGH_VALUE SYS_P1161 2 TEST_PARTITION_HIGH_VALUE SYS_P1162 3 TEST_PARTITION_HIGH_VALUE SYS_P1163 4
Wenn ich jetzt nach dem maximalen HIGH_VALUE suchen will, treffe ich auf die Beschränkungen des LONG-Typs:
select table_name , partition_name , max(high_value) max_high_value from user_tab_partitions where table_name = 'TEST_PARTITION_HIGH_VALUE' group by table_name , partition_name , max(high_value) max_high_value * FEHLER in Zeile 3: ORA-00997: Unzulässige Verwendung des Datentyps
Und das ist dann der Moment, wo das DBMS_XMLGEN-Package interessant wird:
select xmltype(DBMS_XMLGEN.GETXML('select table_name, high_value from user_tab_partitions where table_name = ''TEST_PARTITION_HIGH_VALUE'' ')) AS xml from dual XML ------------------------------------------------------ <?xml version="1.0"?> <rowset> <row> <table_name>TEST_PARTITION_HIGH_VALUE</TABLE_NAME> <high_value>1</HIGH_VALUE> </ROW> <row> <table_name>TEST_PARTITION_HIGH_VALUE</TABLE_NAME> <high_value>2</HIGH_VALUE> </ROW> <row> <table_name>TEST_PARTITION_HIGH_VALUE</TABLE_NAME> <high_value>3</HIGH_VALUE> </ROW> <row> <table_name>TEST_PARTITION_HIGH_VALUE</TABLE_NAME> <high_value>4</HIGH_VALUE> </ROW> </ROWSET>
Die GETXML-Funktion liefert dabei - wenig überraschend - eine XML-Repräsentation der Ergebnisse einer übergebenen Abfrage. Mit Hilfe weiterer Funktionen, die ebenfalls bei Adrian Billington erläutert werden, kann man dieses XML dann wieder parsen:
with xml as ( select xmltype(DBMS_XMLGEN.GETXML('select table_name, high_value from user_tab_partitions where table_name = ''TEST_PARTITION_HIGH_VALUE'' ')) AS xml from dual) , high_values as ( select extractValue(test.object_value, '/ROW/TABLE_NAME') table_name , extractValue(test.object_value, '/ROW/HIGH_VALUE') high_value from xml x , table(xmlsequence(extract(x.xml, '/ROWSET/ROW'))) test ) select * from high_values TABLE_NAME HIGH_VALUE ------------------------------ ---------- TEST_PARTITION_HIGH_VALUE 1 TEST_PARTITION_HIGH_VALUE 2 TEST_PARTITION_HIGH_VALUE 3 TEST_PARTITION_HIGH_VALUE 4
Und diese Ergebnisse kann man dann gruppieren:
with xml as ( select xmltype(DBMS_XMLGEN.GETXML('select table_name, high_value from user_tab_partitions where table_name = ''TEST_PARTITION_HIGH_VALUE'' ')) AS xml from dual) , high_values as ( select extractValue(test.object_value, '/ROW/TABLE_NAME') table_name , extractValue(test.object_value, '/ROW/HIGH_VALUE') high_value from xml x , table(xmlsequence(extract(x.xml, '/ROWSET/ROW'))) test ) , max_values as (select table_name , max(high_value) high_value from high_values group by table_name ) select * from max_values TABLE_NAME HIGH_VALUE ------------------------------ ---------- TEST_PARTITION_HIGH_VALUE 4
Und damit wäre ich wieder einmal um PL/SQL herum gekommen ... - besten Dank an Adrian Billington, dessen Webseite sehr viele relativ komplexe Themen mit sehr handlichen Beispielen erläutert.
Keine Kommentare:
Kommentar veröffentlichen