monaco-sql-languages icon indicating copy to clipboard operation
monaco-sql-languages copied to clipboard

如何根据SQL语句上下文得知别名与实体的关系

Open resetsix opened this issue 1 year ago • 0 comments

Issue 区分

  • 本 Issue:讨论如何通过手动获取上下文来处理 SQL 别名。
  • https://github.com/DTStack/monaco-sql-languages/issues/150 :讨论借助 monaco-sql-languages 实现 SQL 别名的处理。

自动补全方式

实现自动补全的方式有两种:

  1. 前端静态补全:如使用 monaco-sql-languages
  2. 后端动态补全:如使用 LSPLanguage Server Protocol,语言服务器协议)。

核心原理

通过预测用户意图并提供可能的输入选项,基于已输入的内容和上下文信息,推断用户可能想要输入的内容。

实现步骤

  1. 词法分析(Lexical Analysis)

    • 操作:将输入的文本分解为标记(tokens)。
    • 目标:识别出关键字、标识符、运算符等。
  2. 语法分析(Syntactic Analysis)

    • 操作:基于词法分析结果,理解代码结构,构建语法树。
    • 目标:确定当前输入在语法树中的位置。
  3. 语义分析(Semantic Analysis)

    • 操作:理解代码的语义,分析变量作用域、类型信息等。
    • 目标:推断出当前光标位置应该提示什么类型的数据。
  4. 上下文感知(Context Awareness)

    • 操作:结合当前光标位置,分析上下文代码结构及之前的输入。
    • 目标:理解当前环境,确保提示项符合上下文。
  5. 候选项生成(Candidate Generation)

    • 操作:根据词法、语法、语义分析生成可能的补全选项。
    • 目标:生成如关键字、变量名、函数名等补全内容。
  6. 排序和过滤(Sorting & Filtering)

    • 操作:根据上下文的相关性和历史使用频率,对候选项进行排序。
    • 目标:过滤掉不符合当前上下文的无关项,并优化排序。

实现方法

  • 静态分析:基于预定义的语言规则和规范生成补全项。
  • 动态分析:考虑运行时信息和项目特定的上下文(如自定义函数、表别名等)。

数据来源

  • 语言规范:关键字、内置函数等基础补全内容。
  • 项目代码:如自定义别名、函数、变量等。
  • 上下文:用户已输入的代码内容,如库、表等。

AST 与动态编辑的局限

AST(抽象语法树)虽然可以帮助解析 SQL 语句的结构,但它只适合静态分析的场景。

在动态编辑环境中,SQL 语句往往不完整或存在语法错误,此时生成 AST 可能会影响性能。因此AST并不适用于实时编辑器的输入场景。

LSP 的优势

LSP更加适合动态编辑环境,它能够持续分析不完整或有语法错误的代码,并提供自动补全、跳转到定义等功能。通过增量更新可以提高性能,适合实时代码编辑和补全需求。

前端实现表别名与表名映射(重点)

虽然使用LSP有颇多好处,但十分依赖后端服务。

如果站在前端角度来看待自动补全别名处理(这也是monaco-sql-languages正在实现的愿景),可能需要如下步骤:

  1. 使用正则表达式识别 AS 语句或类似别名定义的语句。(无法精准匹配,因为 AS 关键字可以省略)
  2. 维护一个表别名与表名的映射表,记录所有别名和其对应的表名。
  3. 实时更新这个映射表,在用户输入 SQL 语句时,结合光标位置和上下文分析表别名。
  4. Select u. from user AS u语句中假设用户正在输入u.,那么通过查询映射表找到对应的表名(如 user),并提供列的自动补全。

别名处理会更加相对复杂,因为除了表可以作为别名还有字段、计算函数、子查询等等。

目前在前端处理别名映射我并没有想到一个完美解决方案和思路,例如AS关键字省略怎么办?

resetsix avatar Oct 17 '24 02:10 resetsix