SQL Select Anweisung mittels RegEx splitten

Schrödi

Mitglied
Hallo zusammen,

ich bin gerade am verzweifeln!
Ich versuche gerade eine MySQL Select anweisung mittels preg_match in seine Bestandteile zu splitten.

Code:
SELECT
    [rechenoperation|funktionsauswahl]
  spaltenname

  FROM tabelle

    [WHERE bedinungen]
    [GROUP BY spalten]
    [HAVING aggregatfunktionen]
    [ORDER BY spalte [ASC] [DESC]
    [LIMIT [Anfang][Zeilenanzahl]]

D.H., ich möchte jeden Teil (Select bis From, From bis Where, Where bis Group, usw. ) einzeln in einem Array speichern.

Folgendes habe ichschon versucht
PHP:
	$pattern="/(select)(.*)(from)(.*)(where)(.*)(group by)(.*)                     usw.                          /";
	preg_match($pattern, strtolower($this->SQL), $this->splitSQL);

Das funktioniert auch fast, solange alles vorhanden ist. Da aber alles ab dem Where optional in der SQL Anweisung ist, sollte das splitten auch funktionieren, wenn nicht alle Teile vorhanden sind. Fehlt ein Argument, wird ein leeres Array ausgegeben.
Klasse wäre es, wenn das Array im Eneffekt folgendermaßen aussehen könnte:


PHP:
$splitSQL[0] = Select spalte1, spalte2
$splitSQL[1] = From tab 1 Left Join ....
$splitSQL[2] = Where ....

und so weiter und so fort.

Gruß Schrodi
 
EDIT: Ich hatte noch einen kleinen Fehler drin, den hab ich jetzt behoben.

Hi,

sowas begeistert mich immer. Ich hab mal was gebastelt:

PHP:
<?php

$SQL = "SELECT T2.from, T1.num AS c FROM table1 T1, table2 T2 WHERE T1.id=T2.id AND ... ORDER BY c";
$pattern = "/(select .+?)( from .+?(?= where | group by | having | order by | limit |$))( where .+?(?= group by | having | order by | limit |$))?( group by .+?(?= having | order by | limit |$))?( having .+?(?= order by | limit |$))?( order by .+?(?= limit |$))?( limit .+)?/i";
preg_match($pattern, $SQL, $splitSQL);  

$splitSQL = array_map("trim", $splitSQL); // eventuelle Leerzeichen rechts und links entfernen
$splitSQL = array_pad($splitSQL, 8, ""); // Array auf 8 Elemente auffüllen, falls z.B. kein LIMIT-Teil gegeben war

echo "<pre>";
echo $SQL."\n";

print_r($splitSQL);
echo "</pre>";
	
?>


Dieser Code gibt mir:

Code:
SELECT T2.from, T1.num AS c FROM table1 T1, table2 T2 WHERE T1.id=T2.id AND ... ORDER BY c
Array
(
    [0] => SELECT T2.from, T1.num AS c FROM table1 T1, table2 T2 WHERE T1.id=T2.id AND ... ORDER BY c
    [1] => SELECT T2.from, T1.num AS c
    [2] => FROM table1 T1, table2 T2
    [3] => WHERE T1.id=T2.id AND ...
    [4] => 
    [5] => 
    [6] => ORDER BY c
    [7] => 
)

Also ziemlich genau was du wolltest.

Zur Erklärung:

  • Erstmal habe ich alles mit /.../i eingerahmt um case-insensitive zu arbeiten
  • Dann habe ich um die key-Wörter Leerzeichen eingefügt, um nicht etwa einen Tabellennamen wie "comefrom" bei FROM zu matchen
  • Dann habe ich die einzelnen Teile des Queries (SELECT, FROM, WHERE, ...) in Gruppen gepackt und hinter die Optionalen das ? gesetzt (Nur SELECT und FROM sind nicht optional).
  • Dann habe ich den zero-width positive lookahead "(?= ... )" verwendet, um zu sagen, wenn du FROM findest mit irgendetwas dahinter, dann matche das ".+?" auf dieses irgendetwas, wenn es gefolgt wird von WHERE oder GROUP BY oder ... oder eben mit dem Zeilenende "$". Am Ende bei ORDER BY soll er also alles mit ".+?" matchen, was danach kommt, bis zum LIMIT: "( order by .+?(?= limit ))?". Das letzte "?" ist dann wieder weil das ganze ORDER BY optional ist.
  • Dann habe ich zum matchen der einzelnen Teile nicht ".*" verwendet sondern ".+?". "+" weil ja schon mindestens ein Zeichen kommen muss und "?" weil dann non-greedy gematched wird. Also möglichst wenig und nicht schon vorne beim FROM alles bis hinten um LIMIT.

Zum Weiterlesen:
Zero-width positive lookahead
non-greedy matching

Ich hoffe das passt soweit. Bei Fragen, fragen! ;)

Viele Grüße
DJ2K
 
Zuletzt bearbeitet:
Super, danke!

Funktioniert einwandfrei.
Großes Lob an DeeJTwoK!

Kennt vielleicht noch jemand ein gutes Tutorial, dass ich das auch mal soweit verstehe, um sowas selbst basteln zu können? :-)

Gruß Schrodi
 
Zurück