用于正确分割嵌套SQL分隔符的正则表达式


Regex for properly splitting apart nested SQL delimiters

我正在处理一个包含多个SQL查询的字符串:

ALTER TABLE _version ADD test1 INT NOT NULL;
ALTER TABLE _version ADD test2 INT NOT NULL;
CREATE PROCEDURE test3 ()
        LANGUAGE SQL
        DETERMINISTIC
        SQL SECURITY DEFINER
        COMMENT 'A procedure'
        BEGIN
            SELECT 'Hello World !';
        END;

我想把这个字符串分割成三个独立查询的数组,像这样:

ALTER TABLE _version ADD test1 INT NOT NULL;

ALTER TABLE _version ADD test5 INT NOT NULL;

CREATE PROCEDURE test3 ()
        LANGUAGE SQL
        DETERMINISTIC
        SQL SECURITY DEFINER
        COMMENT 'A procedure'
        BEGIN
            SELECT 'Hello World !';
        END;

这将允许我使用PDO进行多个查询。因为不幸的是(据我所知),您不能使用PDO从一条语句中进行多个事务查询。并且不能在PDO查询中使用DELIMITER $$ SQL命令。

但是,请注意BEGINEND之间的;分隔符。这就导致了问题!如果我只是使用;分隔符对字符串进行爆破,它将不能正确地分隔出过程。

我一直在用正则表达式来查找BEGINEND之间的所有内容,然后用其他东西替换这些分隔符(如$$分隔符)-然后做$$分隔符的爆炸-但似乎没有任何工作。

这是一个(坏的)stab在什么我已经尝试在PHP和regex,其中$sqlString是多个查询字符串:

$sqlString = preg_replace("#(?<!BEGIN.+);(?!.+END)#",'$$',$sqlString);
$splitQueries = explode("$$",$sqlString);

但是我不能让消极的向前看/向后看起作用。请帮助我找出正确的正则表达式模式或正确的方向!

免责声明:这只是完全按照您的要求并在;之后分割输入,除非在BEGIN/END语句之间(它将在WHERE column = ';'之类的东西上失败)。

这个PHP语句将做你需要做的事情(RegEx演示):

$splitQueries = preg_split('/(?<=;)(?!(?:(?!BEGIN).)*END)/s', $sqlString);
array_pop($splitQueries); // there is an extra value in the array, assuming
                          // your query ends in ; 

首先,我对分号使用了正面查找,这样您就可以只使用一个简单的preg_split()调用(因为它实际上不会匹配;,而是匹配它后面的空格)。

接下来,我在它后面加上了一个否定的展望:(?!.*END)。这里需要s修饰符,因为它使.匹配换行符。

最后,我用另一个负向前瞻:(?:(?!BEGIN).)*替换了负向前瞻中的.*

我们的最终结果寻找分号(技术上讲,分号后面的空格),然后查看后面的每个字符(除非我们看到BEGIN),以确保没有END(表明我们在BEGIN/END语句中)。乐趣!