简介:我希望有一个库或例程可以做到这一点,但我找不到这样的东西。我真的在寻找方向和建议从哪里开始......
情况如下: 我有一块SQL命令以纯文本形式出现。它可能是一个或几个SQL命令。我需要一种方法来分割多个SQL命令,这样我就可以一次运行一个。 Microsoft SQL Management Studio确实具有开箱即用的此行为。
我正在尝试将此功能添加到在Apache(Debian)上运行的PHP5 / MySQL5应用程序中。
一些要点:
以下是我需要分成两个语句的SQL示例块:
select sMessage,
(
SELECT COUNT(sTag) FROM Tags WHERE ixTicket = note.ixTicket
) FROM note
select * from ticket
WHERE (SELECT MAX(nCount) FROM Counter WHERE ixTicket = ticket.ixTicket) > 5
我尝试了一些RegEx尝试,但这似乎不够强大。
有关解决此问题的方法的任何建议吗?
答案 0 :(得分:3)
我不确定这是否可行。您当然需要深入了解目标DBMS的SQL语法。例如,在我的脑海中,这是一个MySQL声明:
INSERT INTO things
SELECT * FROM otherthings ON DUPLICATE KEY
UPDATE thingness=thingness+1
在某些DBMS中可能存在一些构造,如果没有分隔符,可能会有歧义。
我不想要求用户在每个SQL语句后输入分号。
我想你可能会被迫。它完全是划分SQL语句的标准方法。即使您可以找到一个启发式来检测可能的SQL语句开始点,您也可能会发生意外“DELETE FROM things”-without-WHERE-clause等灾难。
SQL语句可以在一行或多行上,因此我无法在LB / CR上进行包装
是否可以接受双换行换新语句?
我尝试了一些RegEx尝试,但这似乎不够强大。
不,即使带有分号分隔符,正则表达式也远不足以解析SQL。问题点包括:
';'
";"
`;`
'\';'
''';'
-- ;
#;
/*;*/
以及这些结构的任何插入。 EEK!
答案 1 :(得分:1)
也许试试这个库。我以前成功地使用它来解析sql。 http://www.sqlparser.com/
答案 2 :(得分:1)
为定期导致问题的讨论添加一个怪癖:
DECLARE c CURSOR FOR
SELECT * FROM SomeWhere ...
FOR UPDATE
跟踪UPDATE往往会使特殊解析器失去优势。您可能不必担心这一点,因为首先不允许使用DECLARE表示法(实际上是嵌入式SQL,而不是纯SQL)。但是,即使不在DECLARE语句中,FOR UPDATE子句也可以出现在SQL的某些方言中,所以要小心。
答案 3 :(得分:1)
可能使用以下Java Regex?检查测试...
@Test
public void testRegexp() {
String s = //
"SELECT 'hello;world' \n" + //
"FROM DUAL; \n" + //
"\n" + //
"SELECT 'hello;world' \n" + //
"FROM DUAL; \n" + //
"\n";
String regexp = "([^;]*?('.*?')?)*?;\\s*";
assertEquals("<statement><statement>", s.replaceAll(regexp, "<statement>"));
}
答案 4 :(得分:1)
$sMultiQuery = 'SHOW TABLES; SELECT * FROM `test`'; $aQueries = array(); if ( preg_match_all('/([^;]*?((\'.*?\')|(".*?"))?)*?(;\s*|\s*$)/', $sMultiQuery, $aMatches) ) { $aQueries = $aMatches[0]; } else { $aQueries = array($sMultiQuery); } foreach ( $aQueries as $sQuery ) { # Do your thing }
答案 5 :(得分:0)
您最好的选择是要求用户在语句之间放置某种类型的分隔符。例如:要求每个语句用仅包含单词GO或“\”的行描述,或者用“;”结束每个语句。
通过这种方式,您可以轻松地将单个字符串分解为单独的SQL语句。
答案 6 :(得分:0)
如果您不希望用户输入分隔字符,例如';'或者其他任何事情,你需要自己解析输入并有逻辑来确定语句的开始位置。
你的逻辑需要处理显而易见的查询,启动关键字'SELECT','UPDATE','INSERT','DELETE'并向前推进到下一个关键字(或输入结束)。
答案 7 :(得分:0)
您是否尝试过使用关键字'SELECT','UPDATE','INSERT'和'DELETE'以及计算开头次数('和关闭大括号')?
这应该允许您确定避免嵌套的SELECT语句并找到语句的正确结尾。
答案 8 :(得分:0)
您需要使用分号分隔符。从技术上讲,没有它,SQL语句完全无效;任何省略它的人都在编写格式错误的SQL。要求分号以标准化的方式解决所有问题,并使软件易于编写。
或许执行以下操作:如果用户输入的查询不包含一个或多个分号(当然在引号之外),请在末尾添加分号并将其作为单个查询运行。否则,以分号分隔输入的查询并单独运行每个查询,如果省略,可能在最终查询结尾处添加分号。
此解决方案易于编写,符合SQL标准,并且只是简单的工作。不要求分隔符是疯狂的必然途径。
答案 9 :(得分:-1)
我想你可以自己解析它。查找关键字SELECT,DELETE,UPDATE,INSERT,EXEC等
在解析时,如果遇到“(”增加计数器:nest_level ++
如果遇到“)”减少nest_level -
然后当你遇到一个关键字,并且nest_level == 0时,你就会进入下一个声明。
你还必须处理像
这样的案件 INSERT ...
SELECT ....
因此,对于INSERT,您必须寻找SELECT或VALUES ......
毫无疑问是其他情况。
同意kquinn你应该只需要分号。我不认为这有什么“不冷静”。