跳转至

查询解析文法

这里的查询解析包含了对具体某张表的数据的增删查改。注意该部分的指令可能存在性能瓶颈,要求执行完毕后输出总用时,推荐以秒为单位。

where_and_clause

虽然 where_and_clause 只是几个完整文法的一个公用部分,但是本身已经足够复杂,这里单独进行解释。

注意 where_and_clause 是支持 AND 与运算的一系列条件,我们的必做项只对 AND 进行要求。

每一个条件对应一个 where_clause 语句,这里面包含了必做与选做项内容,其格式均为 column+操作符+操作对象。

column 表示当前被筛选的表的列名,其文法中的前后两个 Identifier 分表表示表名和列名,简单起见我们约定当且仅当语句只涉及到一张表时,可以省略前一个 Identifier,此时列名是没有二义性的。

注意 where_operator_selectwhere_in_select 均涉及到嵌套子查询,但前者必须检查子查询 select_table 的返回结果是否有且只有一条,后者子查询返回任意数量条均不影响其执行。

多数条件的含义是显然的,但是一个可能存在争议的点在于字符串匹配的大小写敏感问题。如 MySQL 等数据库系统区分了 nonbinary stringbinary string,一般的 CHARVARCHAR 等类型均为 nonbinary string,其一个重要特点是在进行字符串匹配或比较时不区分大小写。 尽管你可以选择实现得如同 MySQL 一般,但简便起见强烈建议你使用 binary string,用 ASCII 序进行比较,也即区分大小写,相信这对多数语言而言实现起来都会更容易。

SQL的弱类型特性

如 MySQL 等主流 SQL 均采用弱类型,例如在 WHERE 中不会区分字符串与整型,常量 123"123" 通常是等价的。

但是简便起见,强烈建议你采用强类型实现,当类型不匹配时直接报错并拒绝执行指令。

insert_into_table

在当前数据库中名为 Identifier 的现有表中插入若干行新数据。该指令的输出应当包含成功插入的条数。

简便起见我们默认不支持指定列的名称,需要将全部列按顺序给出对应列的值,执行器需要完成数量、类型等检查工作。

可选的,你可以实现扩展语法,手动指定列的名字并只给出对应列的值,其他值自动使用 DEFAULT 值。

由于一次可能插入多条数据,其中可能部分数据有问题,包括破坏完整性约束、类型不匹配、数量不匹配等(下称非法数据),此时你可能采用一些不同的处理手段:

  1. 将所有能插入的数据均插入;
  2. 遇到第一条非法数据时终止执行,但不影响前面数据的插入;
  3. 遇到第一条非法数据时终止执行并回滚,前面数据也不会插入。

由于我们不断简化作业内容后, INSERT 语句不需要指定列名,ALTER 增减列也已经被删除,因此在必做内容里, DEFAULT 值除了在 DESC 中展示外没有任何作用。

delete_from_table

在当前数据库中名为 Identifier 的现有表中删除符合条件的若干行数据。该指令的输出应当包含成功删除的条数。

update_table

在当前数据库中名为 Identifier 的现有表中将符合条件的若干行数据的指定列进行更新。该指令的输出应当包含成功更新的条数。

由于 set_clause 的文法比较简单,这里的 SET 只支持最简单的常量赋值。你也可以考虑扩展文法来支持一些更复杂的更新,例如如何实现形如 SET count = count + 1 这样的更新。

select_table

在当前数据库中名为 Identifier 的现有表中选出符合条件的若干行数据的指定列。该指令的输出应当包含选出来的表格,最后面附带总行数(或者你也可以为你输出的表格的每一行增加行号,则可以省略额外的行数输出)。

对于输出表格的相关要求参考 《0.3 前端约定》 一节关于交互模式的说明,这不是强制要求,但你自己设计的输出也应该包含不少于该说明的信息量。

跨库查询

如 MySQL 等支持多数据库的 DBMS 通常会支持跨库查询,即在 SELECT 语句的 FROM 后指定来自不同数据库的表。我们的大作业对此不做要求,对于涉及到的表名只需要在当前数据库内查找即可。

Authors: Congyuan Rao