为简化的 SQL “where” 子句做 BNF

Doing BNF for a simplified SQL “where” clause

我有以下 SQL 应用了基本 BNF 的语句:

SELECT
    from_expression [, from_expression] ...
FROM
    from_source
WHERE
    condition


from_source:
    table_name

from_expression:
    literal              # 'abc', 1, 
    column               # Table.Field1, Table.Profit
    function             # ABS(...)
    operator invocation  # NOT field1, 2+3, Genres[0], Genres[1:2], Address.name

condition:
    ???

目前 WHERE 条件与 from_expression 相同,但评估为布尔值。显示这一点的正确方法是什么?

语法不关心语义。

从句法上讲,表达式就是表达式,仅此而已。如果您稍后进行某种语义分析,那就是您需要处理差异的时候。您可以在 conditionfrom_expression 的缩减操作中这样做,但在解析时构建 AST 并稍后在树上进行语义分析会更清晰。

一个选项如下,内联示例:

expression:
    literal                                       # 'abc', 1, 
    column                                        # Table.Field1, Table.Profit
    function call                                 # ABS(...)
    operator invocation                           # NOT field1, 2+3, Genres[0], Genres[1:2], Address.name

condition:
    expression { = | != | < | <= | > | >= | IN } expression  # Revenue > 0
    expression IS [NOT] NULL                       # Revenue IS NOT NULL
    condition { AND | OR } condition               # Revenue > 0 AND Profit < 100

这条评论不适合放在评论区。

我犹豫是否要向 LiveSQL 实现提供 link,因为它专门针对 Java 语言,它是开源的,但我们从未添加任何文档。阅读风险自负。

主要的 class 是 LiveSQL.java:在第 113 行,您可以看到 select 子句的主要变体。它有许多变体,但这是允许开发人员根据需要包含尽可能多的结果集列(表达式)的变体:

  public SelectColumnsPhase<Map<String, Object>> select(
      final ResultSetColumn... resultSetColumns) {
    return new SelectColumnsPhase<Map<String, Object>>(this.sqlDialect,
        this.sqlSession, this.liveSQLMapper, false,
        resultSetColumns);
  }

当然,SELECT 子句还有许多其他变体,如果您稍微探索一下,您可以在同一个 class 中找到它们。当我研究所有变体时,我认为我已经非常详尽了。它应该 [大部分] 完整,除了我没有考虑的非标准 SQL 方言变体。

如果您在 WHERE 阶段跟随 QueryBuilder,您可以看到谓词是如何在 SelectFrom.java class 的方法 where(final Predicate predicate)(第 101 行)中组装的,如下所示:

public SelectWherePhase<R> where(final Predicate predicate) {
  return new SelectWherePhase<R>(this.select, predicate);
}

如您所见,WHERE 子句不接受任何类型的表达式。首先,它只接受一个表达式,而不是一个列表。其次,这个表达式必须是谓词(布尔表达式)。当然,这个谓词可以很复杂,混合各种表达式和布尔逻辑。您可以查看 Predicate.java class 以探索所有可以构建的表达式。

条件

我们以上面描述的谓词class为例。如果 pq 是布尔表达式,并且 abc 是 [大部分] 任何类型,您可以将条件表示为:

condition:
  <predicate>

predicate:
  p and q,
  p or q,
  not p,
  ( p ),
  a == b,
  a <> b,
  a > b,
  a < b,
  a >= b,
  a <= b,
  a between b and c,
  a not between b and c,
  a in (b, c, ... )
  a not in (b, c, ... )

当然还有更多的运算符,但这让您了解了它的要点。