用于正确拆分嵌套 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 之间的所有内容,然后将这些分隔符替换为其他内容(例如 $$ 分隔符) -- 然后对 $$ 定界符进行分解 -- 但似乎没有任何效果。

这是我迄今为止在 PHP 和正则表达式中尝试过的(错误的)尝试,其中 $sqlString 是包含多个查询的字符串:

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

但我无法使负面 look-aheads/look-behinds 工作。请帮我找出正确的正则表达式模式或正确的方向!

免责声明: 这完全按照您的要求进行,并在 ; 之后拆分输入,除非在 BEGIN/[ 之间=13=] 语句(它将在 WHERE column = ';'.

之类的情况下失败

此 PHP 语句将完全满足您的需要 (RegEx demo):

$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() 调用(因为它实际上不会匹配 ;,而是匹配 space 在它之后)。

接下来,我紧随其后的是负面前瞻:(?!.*END)。这是需要 s 修饰符的地方,因为它使 . 匹配换行符。

最后,我将否定前瞻中的 .* 替换为另一个否定前瞻:(?:(?!BEGIN).)*.

我们的最终结果寻找一个分号(技术上是紧跟在它后面的 space),然后查看后面的每个字符(除非我们看到 BEGIN)以确保没有 END(表示我们在 BEGIN/END 语句中)。好玩!