2008-09-26 75 views
16

我上周写了一些单元测试,用于生成一些SQL语句的一段代码。正则表达式以匹配常见的SQL语法?

我试图找出一个匹配SELECT,INSERT和UPDATE语法的正则表达式,这样我就可以验证我的方法是否生成有效的SQL,并且在搜索后和我放弃了各种正则表达式编辑器。

我设法获得部分匹配,但由于引号中的某个部分可以包含任何字符,因此它可以快速扩展以匹配整个陈述。

任何帮助将不胜感激,我不是很好的正则表达式,但我想了解更多关于他们。

顺便说一下,它是C#正则表达式,我后。

澄清

我不想需要对数据库的访问,因为这是一个单元测试的一部分,我不wan't不得不维持一个数据库来测试我的代码。这可能比这个项目寿命更长。

回答

36

正则表达式只能匹配有限状态自动机可以解析的语言,这是非常有限的,而SQL是一种语法。 可以证明你不能用正则表达式来验证SQL。所以,你可以停止尝试。

+0

同意。除了正则表达式,还需要其他一些方法。没有办法匹配select语句的合法语法:http://download.oracle.com/docs/cd/B28359_01/server.111/b28286/statements_10002.htm#SQLRF01702 – 2008-09-26 16:24:19

+0

同意。实际上,你需要一个SQL解析器。以下是一篇文章,介绍如何在通用SQL解析器的帮助下进行供应商特定的脱机SQL语法检查:http://www.dpriver.com/blog/list-of-demos-illustrate-how-to-use-general -sql-parser/vendor-specific-offline-sql-syntax-check/ – 2012-01-08 12:15:31

0

您是否尝试过懒惰选择器。尽可能匹配,而不是尽可能匹配,这可能是你需要引用的。

0

我假设你做了类似“。*”的尝试,而不是尝试“[^”] *“,这会阻止你吃掉整条线,它仍然会给你带有” 。

+0

不,我指定\的空格和连字符,它走到行的末尾 – 2008-09-26 14:45:44

1

关闭我的头顶:您是否可以将生成的SQL传递给数据库并在其上使用EXPLAIN并捕获任何可能表明形成不良的SQL的异常?

+0

这对单元测试没有用处,我可能不一定有权访问数据库,我知道它将始终运行 – 2008-09-26 14:47:33

+0

取决于服务器,例如,MySQL只允许在选择的语句中解释。 – pilsetnieks 2008-09-26 15:01:50

0

要验证查询,只需使用SET NOEXEC ON运行它们,这就是Entreprise Manager在解析查询时不执行它的原因。

此外,如果您使用正则表达式来验证sql查询,几乎可以肯定的是,您将错过某些特定情况,或者由于其他原因而导致查询无效,即使它在语法上是正确的。

0

我建议使用相同的模式创建一个数据库,可能使用嵌入式sql引擎,并将sql传递给它。

0

我不认为你甚至需要创建能够验证语句的模式,因为系统不会尝试解析object_name等,直到它成功解析语句为止。

使用Oracle作为一个例子,如果你这样做,你一定会得到一个错误:

select * from non_existant_table; 

在这种情况下,“ORA-00942:表或视图不存在”。

但是,如果你执行:

select * frm non_existant_table; 

然后你会得到一个语法错误, “ORA-00923:FROM关键字未找到预期”。

它应该是可能的分类错误为指示不正确的语法以及与表名和权限等错误语法解析错误..

添加到不同的RDBMS,甚至不同版本的问题,允许不同的语法我认为你真的必须去数据库引擎完成这项任务。

2

据我所知,这超出了正则表达式,并且越来越接近BnF和编译器的黑暗艺术。

http://savage.net.au/SQL/

同样的事情发生在谁想做正确的语法高亮人。你开始把东西塞进正则表达式,然后你最终编写一个编译器......

14

SQL是一个type-2 grammar,它太强大了,不能用正则表达式来描述。这与您决定生成C#代码然后在不调用编译器的情况下验证它是一样的。数据库引擎通常太复杂,不容易被扼杀。

也就是说,你可以试试ANTLR's SQL grammars

0

ANTLR grammars来解析SQL。使用in memory database或者非常轻量级的数据库如sqlite确实是一个更好的主意。从分析的角度来看,测试SQL是否有效似乎很浪费,并且检查表和列的名称以及查询的具体情况会更有用。

1

我有同样的问题 - 一种方法可以用于所有更标准的sql语句,将启动内存中的Sqlite数据库并对其发出查询,如果返回“表不存在“错误,那么你的查询正确解析。

-1
public bool IsValid(string sql) 
{ 
string pattern = @"SELECT\s.*FROM\s.*WHERE\s.*"; 
Regex rgx = new Regex(pattern, RegexOptions.IgnoreCase); 
return rgx.IsMatch(sql); 
} 
0

最好的方法是验证用于创建查询的参数,而不是查询本身。接收变量的函数可以检查字符串的长度,有效的数字,有效的电子邮件或其他。您可以使用正则表达式来执行此验证。