Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>I agree it sounds like a bad choice, but I can think of some situations where splitting a query could be useful.</p> <p>I would try something similar to this, relying heavily on regular expressions for parsing the query. It would work in a very limited of cases, but it's support could be expanded progressively when needed.</p> <pre><code>&lt;?php /** * That's a weird problem, but an interesting challenge! * @link http://stackoverflow.com/questions/5019467/problem-writing-a-mysql-parser-to-split-joins-and-run-them-as-individual-query */ // Taken from the given example: $sql = "SELECT articles.*, formats.format_title FROM articles INNER JOIN formats ON articles.article_format_id = formats.format_id INNER JOIN article_categories ON articles.article_id = article_categories.article_id WHERE article_categories.category_id = 2 ORDER BY articles.article_date DESC"; // Parse query // (Limited to the clauses that are present in the example...) // Edit: Made WHERE optional if(!preg_match('/^\s*'. 'SELECT\s+(?P&lt;select_rows&gt;.*[^\s])'. '\s+FROM\s+(?P&lt;from&gt;.*[^\s])'. '(?:\s+WHERE\s+(?P&lt;where&gt;.*[^\s]))?'. '(?:\s+ORDER\s+BY\s+(?P&lt;order_by&gt;.*[^\s]))?'. '(?:\s+(?P&lt;desc&gt;DESC))?'. '(.*)$/is',$sql,$query) ) { trigger_error('Error parsing SQL!',E_USER_ERROR); return false; } ## Dump matches #foreach($query as $key =&gt; $value) if(!is_int($key)) echo "\"$key\" =&gt; \"$value\"&lt;br/&gt;\n"; /* We get the following matches: "select_rows" =&gt; "articles.*, formats.format_title" "from" =&gt; "articles INNER JOIN formats ON articles.article_format_id = formats.format_id INNER JOIN article_categories ON articles.article_id = article_categories.article_id" "where" =&gt; "article_categories.category_id = 2" "order_by" =&gt; "articles.article_date" "desc" =&gt; "DESC" /**/ // Will only support WHERE conditions separated by AND that are to be // tested on a single individual table. if(@$query['where']) // Edit: Made WHERE optional $where_conditions = preg_split('/\s+AND\s+/is',$query['where']); // Retrieve individual table information &amp; data $tables = array(); $from_conditions = array(); $from_tables = preg_split('/\s+INNER\s+JOIN\s+/is',$query['from']); foreach($from_tables as $from_table) { if(!preg_match('/^(?P&lt;table_name&gt;[^\s]*)'. '(?P&lt;on_clause&gt;\s+ON\s+(?P&lt;table_a&gt;.*)\.(?P&lt;column_a&gt;.*)\s*'. '=\s*(?P&lt;table_b&gt;.*)\.(?P&lt;column_b&gt;.*))?$/im',$from_table,$matches) ) { trigger_error("Error parsing SQL! Unexpected format in FROM clause: $from_table", E_USER_ERROR); return false; } ## Dump matches #foreach($matches as $key =&gt; $value) if(!is_int($key)) echo "\"$key\" =&gt; \"$value\"&lt;br/&gt;\n"; // Remember on_clause for later jointure // We do assume each INNER JOIN's ON clause compares left table to // right table. Forget about parsing more complex conditions in the // ON clause... if(@$matches['on_clause']) $from_conditions[$matches['table_name']] = array( 'column_a' =&gt; $matches['column_a'], 'column_b' =&gt; $matches['column_b'] ); // Match applicable WHERE conditions $where = array(); if(@$query['where']) // Edit: Made WHERE optional foreach($where_conditions as $where_condition) if(preg_match("/^$matches[table_name]\.(.*)$/",$where_condition,$matched)) $where[] = $matched[1]; $where_clause = empty($where) ? null : implode(' AND ',$where); // We simply ignore $query[select_rows] and use '*' everywhere... $query = "SELECT * FROM $matches[table_name]".($where_clause? " WHERE $where_clause" : ''); echo "$query&lt;br/&gt;\n"; // Retrieve table's data // Fetching the entire table data right away avoids multiplying MySQL // queries exponentially... $table = array(); if($results = mysql_query($table)) while($row = mysql_fetch_array($results, MYSQL_ASSOC)) $table[] = $row; // Sort table if applicable if(preg_match("/^$matches[table_name]\.(.*)$/",$query['order_by'],$matched)) { $sort_key = $matched[1]; // @todo Do your bubble sort here! if(@$query['desc']) array_reverse($table); } $tables[$matches['table_name']] = $table; } // From here, all data is fetched. // All left to do is the actual jointure. /** * Equijoin/Theta-join. * Joins relation $R and $S where $a from $R compares to $b from $S. * @param array $R A relation (set of tuples). * @param array $S A relation (set of tuples). * @param string $a Attribute from $R to compare. * @param string $b Attribute from $S to compare. * @return array A relation resulting from the equijoin/theta-join. */ function equijoin($R,$S,$a,$b) { $T = array(); if(empty($R) or empty($S)) return $T; foreach($R as $tupleR) foreach($S as $tupleS) if($tupleR[$a] == @$tupleS[$b]) $T[] = array_merge($tupleR,$tupleS); return $T; } $jointure = array_shift($tables); if(!empty($tables)) foreach($tables as $table_name =&gt; $table) $jointure = equijoin($jointure, $table, $from_conditions[$table_name]['column_a'], $from_conditions[$table_name]['column_b']); return $jointure; ?&gt; </code></pre> <p>Good night, and Good luck!</p>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
    2. VO
      singulars
      1. This table or related slice is empty.
    3. VO
      singulars
      1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload