JOIN ist ein mächtiges Werkzeug, das allerdings auf einen Datenbankserver* beschränkt ist. Wenn dann noch SQL und NoSQL verknüpft werden müssen, steigt der Aufwand schnell in unsinnige Dimensionen. Am Beispiel von MySQL und MongoDB möchte ich zeigen, dass es auch anders geht.
Meine Ausgangssituation war eine MySQL-Tabelle mit (unter anderem) einer MEDIUMTEXT-Spalte. Diese enthielt Fehlerprotokolle, eines je Datenbankzeile und irgendwo in jedem Protokoll gab es die gleiche Meldung:
Message with mail ID 38efbb53c332fb4d9f4a9910 is unhandled.
Die mail-ID stammt aus einer anderen Welt: Es ist eine MongoDB ObjektId. MongoDB-Abfragen bestehen nicht aus SQL-Befehlen, sondern aus einem JSON-Query. Die ID musste also aus dem Fließtext extrahiert und möglichst gleich JSON-Kompatibel ausgegeben werden. Mit SQL ist das sogar möglich:
SELECT GROUP_CONCAT(CONCAT("'",SUBSTRING(error_report,INSTR(error_report,'Message with mail ID ')+21,24),"'")) FROM REPORTS WHERE event_id=171862 LIMIT 2500
Dieses SQL-Query selektiert zunächst (maximal) 2500 Zeilen und zerlegt dann die error_report-Spalte:
- INSTR(error_report,'Message with mail ID ') sucht nach genau diesem Text und gibt die Position des ersten Zeichens innerhalb der Spalte zurück.
- +21 ist notwendig, weil nicht die ganze Zeile, sondern nur die ID selbst ausgeschnitten werden soll. Die folgende SUBSTRING-Funktion setzt dadurch 21 Zeichen später an.
- SUBSTRING(error_report, INSTR()+21, 24) schneidet 24 Zeichen (die festgelegte Länge der ID) aus der error_report-Spalte, beginnend ab dem 21. Zeichen nach der von der INSTR-Funktion gelieferten Position.
- CONCAT(" ' ", SUBSTRING(), " ' ") setzt Anführungszeichen um die gerade ausgeschnittene ID (der besseren Sichtbarkeit wegen habe ich hier Leerzeichen eingefügt).
- GROUP_CONCAT() wiederum setzt alle gefundenen Werte zu einem Feld zusammen und fügt dazwischen jeweils ein Komma ein.
Das Ergebnis ist eine Liste, die sich direkt in ein MongoDB-JSON-Query einsetzen lässt, aber ebenso in einem MySQL SELECT ... WHERE col IN ( ... ) benutzt werden kann.
* Einige Datenbanken (wie beispielsweise Sybase ASE) erlauben die Anbindung anderer Datenbankserver und Abfrage der dortigen Tabellen als wären es lokale. PostgreSQL kann mit Hilfe seiner Foreign Data Wrapper (FDW) MongoDB, MySQL und einige andere Datenbanken direkt implementieren, diese können dann über den Postgres-Server mit SQL-Befehlen abgefragt werden.
3 Kommentare. Schreib was dazu-
Kartin Eberhard
8.08.2014 23:48
Antworten
-
Henri
22.09.2014 22:34
Antworten
-
Sebastian
23.09.2014 6:54
Antworten
Sehr Interessanter Artikel, viele nützliche Informationen die man dadurch sammeln kann und werde sie einsetzten!
Danke für den interessanten Artikel. Wie am Ende erwähnt, gibt es bei anderen DBMS Möglichkeiten direkt fremde Datenbanken zuzugreifen. In MySQL, werden normalerweise dafür Federated-Tables mit einem Perl-Proxy verwendet. Ich weiß aber nicht, ob es auch mit MongoDB geht und man dann wie bei PostgreSQL+MongoDB auch ein Join zwischen MongoDB-Collections und MySQL-Tabellen machen kann. Haben Sie es vielleicht probiert ?
PostgreSQL kann "fremde" Datenbanken direkt ohne Proxy auf dem Datenbankserver einbinden. Sybase macht das gleiche, ob allerdings nicht-Sybase-Datenbanken unterstützt werden, entzieht sich meiner Kenntnis. Von der Proxy-Lösung für MySQL wusste ich noch nichts.
In diesem Fall ging es darum, zwei Datenbanken zu verknüpfen, die zu unterschiedlichen Projekten gehören. Der Aufwand einer gemeinsamen Proxy-Lösung scheint mir für diesen seltenen Anwendungsfall nicht sinnvoll.