【问题标题】:Regular expression to match common SQL syntax?正则表达式匹配常见的 SQL 语法?
【发布时间】:2008-09-26 14:38:08
【问题描述】:

上周我正在为一段生成一些 SQL 语句的代码编写一些单元测试。

我试图找出一个匹配 SELECTINSERTUPDATE 语法的正则表达式,这样我就可以验证我的方法是否生成了有效的 SQL,并且经过 3-4 小时的搜索和各种处理我放弃了正则表达式编辑器。

我设法获得了部分匹配,但因为引号中的部分可以包含任何字符,它会快速扩展以匹配整个语句。

任何帮助将不胜感激,我不太擅长正则表达式,但我想了解更多关于它们的信息。

顺便说一句,我追求的是 C# RegEx。

澄清

我不想访问数据库,因为这是单元测试的一部分,我不想维护数据库来测试我的代码。这可能比项目寿命更长。

【问题讨论】:

标签: sql regex unit-testing


【解决方案1】:

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

【讨论】:

  • 同意。除了正则表达式之外,这里还需要其他一些方法。没有办法匹配 select 语句的合法语法:download.oracle.com/docs/cd/B28359_01/server.111/b28286/…
  • 同意。实际上,您需要一个 SQL 解析器。这里有一篇文章展示了如何在通用 sql 解析器的帮助下进行供应商特定的离线 SQL 语法检查:dpriver.com/blog/…
  • 任何上下文无关的语法都可以被现代正则表达式解析。正则表达式不再局限于解析正则语言。如果这是真的,语言{ a^nb^n } 将无法解析,但是可以通过正则表达式/^(a(\1)?b)$/ 解析。请参阅nikic.github.io/2012/06/15/… 了解更多信息。
  • @Jack 很有趣。这是“标准”功能吗?
  • @Pablo 我相信作为正则表达式的标准功能的反向引用在正则语言中是不允许的,但我现在不确定证据。我知道这个正则表达式不会被很多解析器解析,无论如何,这只是一个例子。重点是“正则表达式”中的“正则”其实是没有意义的。
【解决方案2】:

SQL 是一个type-2 grammar,它太强大了,无法用正则表达式来描述。这就像您决定生成 C# 代码然后在不调用编译器的情况下对其进行验证一样。数据库引擎一般来说太复杂了,不容易被存根。

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

【讨论】:

  • 任何上下文无关的语法都可以被现代正则表达式解析。正则表达式不再局限于解析正则语言。如果这是真的,语言{ a^nb^n } 将无法解析,但是可以通过正则表达式/^(a(\1)?b)$/ 解析。请参阅nikic.github.io/2012/06/15/… 了解更多信息。
  • @Jack,好点子!那么 ANSI SQL SELECT 的 C# 正则表达式是什么?
【解决方案3】:

据我所知,这超出了正则表达式和您接近 BnF 和编译器的黑暗艺术的范围。

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

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

【讨论】:

    【解决方案4】:

    我遇到了同样的问题 - 一种适用于所有更标准 sql 语句的方法是启动内存中的 Sqlite 数据库并针对它发出查询,如果你得到一个“表不存在”错误,然后您的查询正确解析。

    【讨论】:

      【解决方案5】:

      在我脑海中浮现:难道你不能将生成的 SQL 传递到数据库并对其使用 EXPLAIN 并捕获任何表明 SQL 格式不正确的异常吗?

      【讨论】:

      • 这对于我可能不一定有权访问数据库的单元测试没有用,我知道该数据库将始终运行
      • 取决于服务器,例如 MySQL 只允许对 select 语句进行解释。
      【解决方案6】:

      您是否尝试过惰性选择器。它们不是尽可能匹配,而是尽可能少匹配,这可能是引号所需要的。

      【讨论】:

        【解决方案7】:

        要验证查询,只需使用SET NOEXEC ON 运行它们,当您解析查询而不执行查询时,Entreprise Manager 就是这样做的。

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

        【讨论】:

          【解决方案8】:

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

          【讨论】:

            【解决方案9】:

            我认为您甚至不需要创建架构来验证语句,因为系统在成功解析语句之前不会尝试解析 object_name 等。

            以 Oracle 为例,如果这样做肯定会出错:

            select * from non_existant_table;
            

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

            但是如果你执行:

            select * frm non_existant_table;
            

            然后你会得到一个语法错误,“ORA-00923: FROM keyword not found where expected”。

            应该可以将错误分类为表示不正确语法的语法解析错误和与表名和权限等相关的错误。

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

            【讨论】:

              【解决方案10】:

              ANTLR grammars解析SQL。使用in memory database 或非常轻量级的数据库(例如sqlite)确实是一个更好的主意。从解析的角度测试 SQL 是否有效对我来说似乎很浪费,而检查表名和列名以及查询的细节更有用。

              【讨论】:

                【解决方案11】:

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

                【讨论】:

                  【解决方案12】:
                  public bool IsValid(string sql)
                  {
                  string pattern = @"SELECT\s.*FROM\s.*WHERE\s.*";
                  Regex rgx = new Regex(pattern, RegexOptions.IgnoreCase);
                  return rgx.IsMatch(sql);
                  }
                  

                  【讨论】:

                    【解决方案13】:

                    我假设你做了类似.\* 尝试而不是[^"]* 这样可以防止你吃掉整条线。如果字符串中有\,它仍然会给出误报。

                    【讨论】:

                    • 不,我指定了 \s 空格和连字符,它走到了行尾
                    猜你喜欢
                    • 2021-07-11
                    • 2012-04-15
                    • 2010-10-30
                    • 1970-01-01
                    • 2017-10-27
                    • 1970-01-01
                    • 1970-01-01
                    • 2017-08-09
                    • 1970-01-01
                    相关资源
                    最近更新 更多