用PHP中的正则表达式解析WHERE子句

时间:2013-08-20 14:53:48

标签: php mysql regex

我需要从“WHERE”子句中检索表父子关系,如下所示:

select ... large list of fields with aliases ...
from ... list of joined tables ...

where ((`db_name`.`catalog`.`group` = `db_name`.`catalog_group`.`iden`) 
and (`db_name`.`catalog`.`iden` = `db_name`.`catalog_sub`.`parent`))

是否有一些正则表达式从每个条件中获取标识符?比如左边的数组元素[0] =表格,元素[1]是右边的表格。 Ident的名字可能是任何名字。因此,只有像'where''和''='这样的sql运算符可能是键。

非常感谢任何帮助。

CLARIFY

我不想通过WHERE子句从WHERE子句获取引用。我只是想要参考。所以我可以看到可能有正则表达式替换所有序列

`.` 

. 

然后按

匹配所有反对的对
` @ ` = ` @ `

默认情况下,任何可能查询中始终存在标识符的反引号。默认情况下,所有字符串值都用双引号括起来。我认为这对正则表达式大师来说不是一项复杂的任务。提前谢谢。

PS这是因为myISAM引擎不支持我手动恢复的引用。

结束于:

public function initRef($q) {

    $s = strtolower($q);
    // remove all string values within double quotes
    $s = preg_replace('|"(\w+)"|', '', $q); 
    // split by 'where' clause
    $arr = explode('where', $s); 
    if (isset($arr[1])) { 
        // remove all spaces and parenthesis
        $s = preg_replace('/\s|\(|\}/', '', $arr[1]); 
        // replace `.` with .
        $s = preg_replace('/(`\.`)/', '.', $s);
        // replace `=` with =           
        $s = preg_replace("/(`=`)/", "=", $s); 
         // match pairs within ticks
        preg_match_all('/`.*?`/', $s, $matches);
        // recreate arr
        $arr = array();
        foreach($matches[0] as &$match) {
            $match = preg_replace('/`/', '', $match); // now remove all backticks
            $match = str_replace($this->db . '.', '', $match); // remove db_name
            $arr[] = explode('=', $match); // split by = sign
        }
        $this->pairs = $arr; 
    } else {
        $this->pairs = 0;
    }

}

1 个答案:

答案 0 :(得分:2)

使用正则表达式似乎对您没有帮助。如果有子查询怎么办?如果您的查询包含一个包含文本“WHERE”的字符串,该怎么办? Hakre在上面的评论中提到过它,但你最好的选择是使用可以解释你的SQL的东西,这样你才能找到真正合适的WHERE子句和什么不是。

如果你坚持以“错误”的方式而不是使用一些上下文感知解析器,你必须找到WHERE子句,例如:

$parts = explode('WHERE', $query);

假设查询中只有一个WHERE子句,$parts[1]将包含WHERE以后的所有内容。之后你必须检测所有可能跟随的有效子句,如ORDER BY,GROUP BY,LIMIT等,并在那里中断你的字符串。像这样:

$parts = preg_split("/(GROUP BY|ORDER BY|LIMIT)|/", $parts[1]);
$where = $parts[0];

您必须检查文档中的SQL风格以及要支持的查询类型(SELECT,INSERT,UPDATE等),以获取要拆分的完整关键字列表。

之后,它可能有助于删除所有括号,因为优先级与您的问题无关,并且它们使解析更难。

$where = preg_replace("/[()]/", "", $where);

从那时起,您必须再次拆分以找到所有单独的条件:

$conditions = preg_split("/(AND|OR|XOR)/", $where);

最后,您必须拆分运算符以获取右侧和左侧值:

foreach ($conditions as $c)
{
    $idents = preg_split("/(<>|=|>|<|IS|IS NOT)/");
}

您必须检查运营商列表并在需要时添加。 $idents现在包含所有可能的标识符。

您可能需要注意,其中一些步骤(至少在最后一步)还需要修剪字符串才能正常工作。

免责声明:,我认为这是一个非常糟糕的主意。此代码仅在只有一个WHERE子句时才有效,即使这样,它依赖于很多假设。复杂的查询可能会破坏此代码。请改用SQL解析器/解释器。