用于正确拆分嵌套 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 命令。
但是,请注意 BEGIN
和 END
之间的 ;
分隔符。这导致了问题!如果我只是简单地使用 ;
分隔符分解字符串,它就不会正确地分离出过程。
我一直在使用正则表达式来查找不在 BEGIN
和 END
之间的所有内容,然后将这些分隔符替换为其他内容(例如 $$
分隔符) -- 然后对 $$
定界符进行分解 -- 但似乎没有任何效果。
这是我迄今为止在 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
语句中)。好玩!
我正在处理一个包含多个 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 命令。
但是,请注意 BEGIN
和 END
之间的 ;
分隔符。这导致了问题!如果我只是简单地使用 ;
分隔符分解字符串,它就不会正确地分离出过程。
我一直在使用正则表达式来查找不在 BEGIN
和 END
之间的所有内容,然后将这些分隔符替换为其他内容(例如 $$
分隔符) -- 然后对 $$
定界符进行分解 -- 但似乎没有任何效果。
这是我迄今为止在 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
语句中)。好玩!