2

次のように、「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`))

各条件から識別子を取得する正規表現はありますか? 配列 element[0] = table の左側から、element[1] は右側からの table とします。Ident の名前は任意です。そのため、'where' 'and' '=' などの SQL 演算子のみがキーになる可能性があります。

どんな助けでも大歓迎です。

明らかにする

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;
    }

}
4

1 に答える 1

2

正規表現を使用しても役に立たないようです。サブクエリがある場合はどうなりますか?クエリに「WHERE」というテキストを含む文字列が含まれている場合はどうなるでしょうか。Hakre は上記のコメントでそれについて言及しましたが、最善の策は実際に SQL を解釈できるものを使用して、実際に適切な WHERE 句とそうでないものを見つけることができるようにすることです。

コンテキスト認識パーサーを使用する代わりに、これを「間違った」方法で行うことに固執する場合は、たとえば次のように WHERE 句を見つける必要があります。

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

クエリに WHERE 句が 1 つしかないと仮定すると$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 句が 1 つしかない場合にのみ機能し、その場合でも多くの仮定に依存します。複雑なクエリは、おそらくこのコードを壊します。代わりに SQL パーサー/インタープリターを使用してください。

于 2013-08-20T15:43:30.720 に答える