XML-Funktionen ExtractValue und UpdateXML

Hi,

unterstützt PostgreSQL in irgendeiner Version die XML-Funktionen ExtractValue und UpdateXML? Das scheinen ja die beiden Funktionen zu sein, um die es geht, wenn eine Datenbank “XML” kann. Und das können mittlerweile wohl recht viele (MySQL, Oracle, wer noch?). Leider hab ich in der PostgreSQL-Doku und im Web nichts dazu gefunden. Ist XML-Unterstützung hier noch nicht angekommen? Ich bin normalerweise eher bei MySQL zuhause, hatte aber schon den Eindruck, dass PostgreSQL die Trends setzt…

Im Handbuch sind alle XML Funktionen aufgelistet:
http://www.postgresql.org/docs/current/static/functions-xml.html

extractValue() ist zwar nicht dabei aber kann im Grunde durch die xpath() Funktion ersetzt werden.

Einen direkten Ersatz für updateXML() gibt es meines Wissens nicht.

Hm, also ist PostgreSQL nicht kompatibel mit anderen Datenbankservern? Wenn ich eine Anwendung schreibe, die auf verschiedenen Datenbanken funktionieren soll, muss ich also doch wieder die SQL-Abfrage an das Datenbanksystem anpassen… Gibt’s eine Möglichkeit, eine ExtractValue-Funktion mit der richtigen Parameterreihenfolge zu erstellen? Oder ist das für neuere Versionen vorgesehen? Wär ja blöd sonst. Ich hab schon eine längere SQL-Abfrage separat für PGSQL umgeschrieben, weil das System damit nicht zurecht gekommen ist, in anderen Datenbanken hat’s dagegen funktioniert. Ich hatte gehofft, das wäre eine traurige Ausnahme… Oder ich verwende kein XML, wobei ich dann aber ganz andere Probleme bekomme, in jedem DBMS. Dann lieber XML und kein PGSQL.

Obwohl SQL ein “Standard” ist, ist der Dialekt bei jedem DBMS anders.
Das hat nicht direkt was mit der XML Unterstützung zu tun.

Gibt’s eine Möglichkeit, eine ExtractValue-Funktion mit der richtigen Parameterreihenfolge zu erstellen?

Wenn ich das richtig sehe, ist extractValue() genau das gleiche wie das XPath() von Postgres. Sowas wie:

CREATE FUNCTION extractvalue(xml_data xml, xpath_expr text)
  RETURNS text
  LANGUAGE plpgsql
as
$body$
BEGIN
  RETURN xpath(xpath_expr, xml_data);
END
$body$

Aber wenn Du wirklich auf eine komplette XML Unterstützung angewiesen bist, wirst Du auch mit MySQL nicht weit kommen. Soweit ich weiß hat MySQL keinen XML Datentyp und kann auch keinen Index über einen XPath Ausdruck anlegen - unverzichtbar für performante Abfragen in großen Datenmengen.

Die beste XML Unterstützung findest Du derzeit bei DB2 (auch in der kostenlosen Version)

Ich hab schon eine längere SQL-Abfrage separat für PGSQL umgeschrieben, weil das System damit nicht zurecht gekommen ist, in anderen Datenbanken hat’s dagegen funktioniert. Ich hatte gehofft, das wäre eine traurige Ausnahme…

Das Problem hast Du immer wenn Du SQL für mehr als ein DBMS schreiben möchtest, egal ob Du mit XML oder “Standard” SQL arbeitest.

Im Übrigen: nur weil es in “anderen” Systemen funktioniert, heisst ja noch lange nicht, dass die “anderen” es richtig machen - hauptsächlich deswegen weil es kein “richtig” (oder “falsch”) gibt.

Oder die anderen nicht kompatibel mit PostgreSQL?
Egal wie herum man das betrachtet: es gibt einen SQL-Standard, der definiert, was Datenbanken können sollten.
Nur ist die Realität so, dass dieser Standard aus den Sachen “extrahiert” wird, die schon in unterschiedlicher Ausfertigung in den Datenbanken am Markt implementiert sind.


Wenn ich eine Anwendung schreibe, die auf verschiedenen Datenbanken funktionieren soll

Ich führe diesen Satz mal fort:
… musst du jede Datenbank einzeln behandeln.
Das fängt schon bei grundlegenden Funktionen an, die entweder anders heißen, anders implementiert sind oder nur in einigen Datenbanken vorhanden sind.
Dann gibt es noch weitere Unterschiede in der Syntax und im Verhalten der Datenbank.


Ich hab schon eine längere SQL-Abfrage separat für PGSQL umgeschrieben, weil das System damit nicht zurecht gekommen ist, in anderen Datenbanken hat’s dagegen funktioniert.

Welche Anfrage war das, und was sind die Inhalte deiner Menge “andere Datenbanken”?
Woran genau hat es gelegen?


Nun, um das zusammenzufassen:
Viele Anwendungen implementieren oder nutzen eine Zwischenschicht, die sich um die Kommunikation mit der Datenbank kümmert. Die Anwendung selbst sagt dem Layer bloß: ich brauche das und das oder will das und das erledigt haben. Wie genau das erledigt wird, darum kümmert sich dann der jeweilige Datenbanktreiber.

Das war eine Abfrage mit Sub-Selects und noch komplizierterem Zeug. Das Problem war, dass PGSQL sie als syntaktisch falsch abgewiesen hat. Dann hab ich sie so umgeschrieben, dass es funktioniert hat, diese Version wurde aber von MySQL und SQLite abgewiesen.

Eine Zwischenschicht kann ich nicht gebrauchen, weil die auf diesem Abstraktionsniveau nicht viel mehr als einfache Selects können dürften. Oder weil sie sonst noch viel komplizierter zu verwenden sind als SQL es schon ist. Und wenn sie wirklich eine 2 Seiten lange Abfrage so verstehen und umstellen können, dass sie von mehreren DBMS verstanden wird, dann braucht das System dafür bestimmt länger als die Datenbank zur Ausführung, und das ist ebenso inakzeptabel.

Einfache Anpassungen mache ich in meinem Programm auf Textebene. Ich suche nach bestimmten Mustern (sind grad nicht so viele) und ersetze sie durch was anderes, bevor die Abfrage ausgeführt wird. Mit Funktionsnamen könnte ich das schon auch machen, aber Parameter vertauschen wird dabei vermutlich unzuverlässig oder aufwändig.

Naja, wie auch immer, ich weiß jetzt, wie man XML in PGSQL verwenden kann. Mittlerweile hab ich mein Tabellenschema aber eh etwas geändert, so dass ich aktuell keinen akuten Bedarf mehr dafür habe. Danke trotzdem für die Infos.

Ausgehend von deiner gewählten Menge an Datenbanken hatte allerdings höchstwahrscheinlich PG Recht.
PostgreSQL hält sich sehr stark an den SQL-Standard, während das speziell bei MySQL nicht der Fall ist.
SQLite ist eine andere Geschichte, diese Datenbank ist nicht für komplizierte Operationen vorgesehen.


Eine Zwischenschicht kann ich nicht gebrauchen, weil die auf diesem Abstraktionsniveau nicht viel mehr als einfache Selects können dürften.

Du siehst das falsch … erst die Zwischenschicht generiert überhaupt das SQL. Deine Anwendung hat mit SQL nichts mehr zu tun sondern sagt bloß “ich brauche” und “ich will”.


Und wenn sie wirklich eine 2 Seiten lange Abfrage so verstehen und umstellen können, dass sie von mehreren DBMS verstanden wird, dann braucht das System dafür bestimmt länger als die Datenbank zur Ausführung, und das ist ebenso inakzeptabel.

Hier ist dein Denkfehler: da der Datenbanklayer das SQL zusammenstellt, kann dies angepasst an die jeweilige Datenbank erfolgen. Mit allen Features und Performanceoptimierungen, die möglich sind.
Das ganze wird danach also schmerzfreier und performanter als jetzt.

Ähm, macht mich neugierig: wie definiert man in seiner Anwendung eine Abfrage? Ohne SQL?

Andreas

Die Anwendung sagt der Zwischenschicht nur was sie braucht oder was erledigt werden soll.
Der Datenbank Layer erstellt daraus das jeweils für die Datenbank passende SQL.

Ja. Aber wie erfolgt das? Ist das eine Meta-Sprache, hat man da ein buntes Klick-Tool, ‘sieht’ man, was für Tabellen und Felder real da sind?

Andreas

Genau das wär auch meine Frage. Jetzt sag ich der Datenbank mit SQL, was ich will. Ohne SQL geht das dann genau wie? Vielleicht mit Zwischenschicht-spezifischem SQL? :wink: Und wenn es auch eine textuelle Sprache ist, dann muss die ja zusätzlich analysiert und verstanden werden. Wenn es keine textuelle Sprache sondern ein Funktions-API ist, brauche ich wohl sehr viele Funktionen und noch längeren Code, um die SQL-Fähigkeiten zu formulieren.

Hängt von der Programiersprache ab. In Java würde sowas über Hibernate (bzw. JPA) oder einen ähnlichen Layer gehen.

In den meisten Fällen werden solche Schichten aber immer nur wenig DBMS spezifische Features verwenden da sie versuchen alles auf einen gemeinsamen Nenner zu bringen.

Optimierungen werden in seltensten Fällen DBMS spezifsich vorgenommen (z.B. ein CTE um wiederkehrende sub-queries zu optimieren, Windowing Functions um unterschiedliche Aggregate “in einem Rutsch” zu lesen, Kenntnis über Index-Only Retrievals um z.B. wirklich nur benötigte Spalten in’s SELECT mit aufzunehmen, und, und, und…).

Wenn man sich so einen Layer “von Hand” baut wäre das zwar denkbar, aber der Aufwand ist schon enorm.

Letztendlich bedeutet “datenbankunabhängig”, dass es auf allen DBMS gleichmässig langsam läuft, aber auf keinem richtig schnell.

Das ist doch dir als Entwickler überlassen.
Das können Klassen mit entsprechenden Funktionen sein. Das kann eine Funktion pro Funktionalität sein, die du brauchst. Das kann über globale Variablen (häßlich) oder übergebene Parameter gesteuert werden.

Schau dir mal AdoDB und Konsorten an, die bilden so etwas “in einfach” ab. Dort hast du ein definiertes Interface, das du aus deiner Anwendung aufrufst. Ob die Datenbank jetzt z. B. LIMIT und OFFSETT kann oder nicht interessiert dich nicht mehr. Der Layer übernimmt diese Arbeit.

Ähnlich kann man für die gewünschten Funktionalitäten in der Anwendung vorgehen: man definiert, was man benötigt. Das Datenbankinterface erledigt die eigentliche Arbeit.

Ein ORM (Object Relation Mapper) kann doch fast gar nichts. Der nimmt mir die Tipparbeit ab, aber richtige Datenbankabfragen macht der nicht. Und ADOdb für PHP (nicht zu verwechseln mit Microsoft ADODB…) scheint sich eher auf Verbindung und Datenabruf zu beziehen als auf die Abfrage selbst. Das ist ja auch alles einfach. Ich habe Abfragen, die mehrere verschachtelte Sub-Selects und etliche Bedingungen, teils mit Gruppierung und Sortierung verwenden. Die Datenbank hat den Index, die kann das am schnellsten durchführen. Wenn ich erst die Datenbank in den Speicher einlese und dort das auswählen anfange (wie in ADO.NET), dauert es natürlich 20x so lange. Und Geschwindigkeit ist ein kritischer Faktor, eigentlich ist die eine lange Abfrage schon zu langsam… Ich kann sie hier leider nicht am Stück angeben, weil sie auf mehreren Seiten PHP-Code erstellt wird. Letztens hab ich das aber mal grob umgebaut und ein paar der Subselects durch vorherige separate Abfragen ersetzt. Vielleicht kann ich mir die PGSQL-Unterscheidung mittlerweile auch wieder sparen. Hab’s noch nicht probiert.

AboDB und Co. waren nur als Beispiel gedacht. Die werden jedoch nicht performanter als selbst geschriebene Abfragen, nur langsamer.

Auf dem gleichen Weg könntest du in deiner Applikation jedoch auch Datenbankunabhängigkeit einbauen. Bei Nutzung von AdoDB selbst weißt du im besten Fall ja auch nicht, welche Datenbank gerade verwendet wird.