• 3 min read

如何将自然语言完美转换为SQL与关系代数


在学习数据库的过程中,最大的痛点就是:如何把人类常说的“自然语言”需求,准确无误地翻译成“关系代数”甚至是“SQL语句”?

今天,我们将通过一个经典的数据库模型,教大家一个万能的“三步拆解法”。为了让大家能直观地看到查询全貌,我们在进行转换演示前,先放出对应的基础数据表。

1. 基础数据准备:经典的 S-P-J-SPJ 数据库

我们假设有一个供应商、零件、工程项目的管理系统,包含以下四张表:

S 表(供应商表 Supplier)

SNO (供应商号)SNAME (供应商名)STATUS (状态)CITY (所在城市)
S1精益20天津
S2盛锡10北京
S3东方红30北京

P 表(零件表 Part)

PNO (零件号)PNAME (零件名)COLOR (颜色)WEIGHT (重量)
P1螺母12
P2螺栓绿17
P3螺丝刀14

J 表(工程项目表 Project)

JNO (工程号)JNAME (工程名)CITY (所在城市)
J1三建北京
J2一汽长春

SPJ 表(供应情况表 Supply)

SNO (供应商号)PNO (零件号)JNO (工程号)QTY (供应数量)
S1P1J1200
S1P2J1100
S2P1J1300

2. 核心秘籍:三步拆解法

面对复杂的自然语言描述,不要慌,按照这三步来“解构”句子:

  1. 找“目标”(对应关系代数的投影 π\pi 和 SQL 的 SELECT: 看句子最后问的是什么(例如“求…的号码”)。这决定了结果集中需要保留哪些列。
  2. 找“范围”(对应关系代数的自然连接 \bowtie 和 SQL 的 FROM/JOIN: 根据目标和条件,判断这些信息分散在哪些表里。如果跨越了多个表,就需要将它们通过共同的属性连接起来。
  3. 找“条件”(对应关系代数的选择 σ\sigma 和 SQL 的 WHERE: 寻找句子中的限制性定语(例如“红色的”、“天津的”)。

3. 实战演练

让我们结合上面的具体表数据,来看看这个方法如何应用。

场景一:单表简单条件查询

自然语言:求供应工程 J1 零件的供应商号码 SNO。

  • 找目标:供应商号码 SNO \rightarrow πSNO\pi_{SNO} / SELECT SNO
  • 找范围:已知工程号查供应商号,一张“供应情况表 SPJ”就包含了这俩字段 \rightarrow 操作对象为 SPJ 表 / FROM SPJ
  • 找条件:工程为 J1 \rightarrow σJNO=J1\sigma_{JNO='J1'} / WHERE JNO='J1'

最终转换结果:

  • 关系代数πSNO(σJNO=J1(SPJ))\pi_{SNO}(\sigma_{JNO='J1'}(SPJ))
  • SQL语句
    SELECT SNO FROM SPJ WHERE JNO='J1';

(对照数据表:查询 SPJ 表中 JNO 为 J1 的记录,结果将返回 S1, S2)

场景二:多表连接的复杂查询

自然语言:求供应工程 J1 零件为红色的供应商号码 SNO。

  • 找目标:供应商号码 SNO \rightarrow πSNO\pi_{SNO} / SELECT SNO
  • 找范围:涉及工程号(SPJ表)、零件颜色(P表),目标是供应商号(SPJ表)。需要跨表将 SPJ 和 P 连起来 \rightarrow \bowtie / FROM SPJ, P
  • 找条件:工程为 J1 且颜色为红色,同时别忘了隐含的表连接条件(两表的零件号必须相等) \rightarrow σJNO=J1COLOR=\sigma_{JNO='J1' \wedge COLOR='红'} / WHERE JNO='J1' AND SPJ.PNO=P.PNO AND COLOR='红'

最终转换结果:

  • 关系代数πSNO(πSNO,PNO(σJNO=J1(SPJ))πPNO(σCOLOR=(P)))\pi_{SNO}(\pi_{SNO, PNO}(\sigma_{JNO='J1'}(SPJ)) \bowtie \pi_{PNO}(\sigma_{COLOR='红'}(P)))
  • SQL语句
    SELECT SNO 
    FROM SPJ, P 
    WHERE JNO='J1' 
      AND SPJ.PNO=P.PNO 
      AND COLOR='红';

(对照数据表:P表中红色的零件是P1,再看SPJ表中供应P1给J1的供应商,结果将返回 S1, S2)

场景三:处理特殊逻辑(“没有/不”)

自然语言:求没有使用天津供应商生产的红色零件的工程项目代码 JNO。

  • 解题思路:遇到“没有”,通常使用**差运算(-)**或 SQL 的 NOT IN。先求出“所有”的工程号,再减去“使用了天津供应商红色零件”的工程号。

最终转换结果:

  • 关系代数πJNO(J)πJNO(πSNO(σCITY=(S))πSNO,PNO,JNO(SPJ)πPNO(σCOLOR=(P)))\pi_{JNO}(J) - \pi_{JNO}(\pi_{SNO}(\sigma_{CITY='天津'}(S)) \bowtie \pi_{SNO, PNO, JNO}(SPJ) \bowtie \pi_{PNO}(\sigma_{COLOR='红'}(P)))
  • SQL语句
    SELECT JNO 
    FROM SPJ 
    WHERE JNO NOT IN (
        SELECT JNO 
        FROM SPJ, P, S 
        WHERE S.CITY='天津' 
          AND COLOR='红' 
          AND S.SNO=SPJ.SNO 
          AND P.PNO=SPJ.PNO
    );

总结

万变不离其宗。下次遇到再长的自然语言需求,只需拿起笔:画圈标出要查询的最终结果(SELECT),划横线标出涉及的实体名词(FROM),打括号标出限制条件(WHERE)。