diff --git a/README.md b/README.md index e07c7a9..adeb856 100644 --- a/README.md +++ b/README.md @@ -58,6 +58,8 @@ from 当然,以上只是一个示例,真实大数据离线分析的场景下,SQL 可比这复杂 N 倍! +如果感兴趣的话,欢迎往下看文档,还有更复杂的示例~ + ## 优势 1. 支持在线编辑 JSON 和 SQL,支持代码高亮、语法校验、一键格式化、查找和替换、代码块折叠等,体验良好 @@ -99,6 +101,72 @@ from `@xxx(yy = 1 ||| zz = #{变量})`:引用其他 SQL,可传参,参数可再用变量来表示,使用 |||(三个竖线)来分隔参数。 +## 复杂示例 + +需求:用一句 SQL 查询出以下表格 + +![](./doc/assets/complex-example.png) + +这个表格的难点在哪? + +1. 查汇总和查明细的粒度不同,不能用 group by 区分,只能用 union(红色) +2. 分类列中不同行的数据有交叉,不能用 group by 区分,只能用 union( +3. 每一列由多张表共同 join 而成,且不同分类可关联的表不同,须进行区分(灰色表示无法关联),并将缺失的字段补齐(否则无法 union) +4. 不同行的同一列计算公式可能不同(蓝色) +5. 不同列的过滤条件不同(比如最后两列墨绿色是要查全校,其余列只查 1 年级) +6. 要查询同环比,只能用 2 份完整的数据去 join 然后错位计算来得出 + +显然,这个表中很多查询逻辑是重复但又不同的。 + +这么算下来,最后这个 SQL 中到底会包含多少个基础表的 select 呢?每个基础表查询要重复编写多少遍呢? + +然而,这个表格也只是鱼皮对实际需求简化后才得来的,实际需求比这还复杂几倍! + +可想而知,人工写有多恶心?! + +但是使用本工具,只需编写如下结构化的 JSON: + +```json +{ + "main": "select (a / b - 1) from (@查整体(date = 今天)) a, (@查整体(date = 昨天)) b", + "查整体": "@查年级() union @查1班() union @查2班() where date = #{date}", + "查年级": "@查汇总_性别汇总() union @查汇总_性别分组() union @查汇总_爱好汇总() union @查汇总_爱好分组() union @查汇总_电脑类别汇总() union @查汇总_电脑类别分组()", + "查汇总_性别汇总": "@查除电脑关联表()", + "查汇总_性别分组": "@查除电脑关联表() group by 性别", + "查汇总_爱好汇总": "@查除电脑关联表()", + "查汇总_爱好分组": "@查除电脑关联表() where 爱好 in (xx) group by 爱好", + "查汇总_电脑类别汇总": "@查除三连和学习表()", + "查汇总_电脑类别分组": "@查除三连和学习表() group by 电脑类别", + + "查1班": "@查1班_性别汇总() union @查1班_性别分组() union @查1班_爱好汇总() union @查1班_爱好分组() union @查1班_电脑类别汇总() union @查汇总_电脑类别分组()", + "查1班_性别汇总": "@查除电脑关联表() where 1班", + "查1班_性别分组": "@查除电脑关联表() where 1班 group by 性别", + "查1班_爱好汇总": "@查除电脑关联表() where 1班", + "查1班_爱好分组": "@查除电脑关联表() where 1班 and 爱好 in (xx) group by 爱好", + "查1班_电脑类别汇总": "@查除三连和学习表() where 1班", + "查1班_电脑类别分组": "@查除三连和学习表() where 1班 group by 电脑类别", + + "查2班": "@查2班_性别汇总() union @查2班_性别分组() union @查2班_电脑类别汇总() union @查2班_电脑类别分组()", + "查2班_性别汇总": "@查除电脑关联表() where 2班", + "查2班_性别分组": "@查除电脑关联表() where 2班 group by 性别", + "查2班_电脑类别汇总": "@查除三连和学习表() where 2班", + "查2班_电脑类别分组": "@查除三连和学习表() where 2班 group by 电脑类别", + + "查所有关联表": "@查信息表() left join (@查三连表()) left join (@查学习表()) left join (@查电脑表()) left join (@查全校信息())", + "查除电脑关联表": "@查信息表() left join (@查三连表()) left join (@查学习表()) left join (@查全校信息())", + "查除三连和学习表": "@查信息表() left join (@查电脑表()) left join (@查全校信息())", + "查信息表": "select 字段 from 信息表 where 年级 = 1", + "查三连表": "select 字段 from 三连表 where 年级 = 1", + "查学习表": "select 字段 from 学习表 where 年级 = 1", + "查电脑表": "select 字段 from 电脑表 where 年级 = 1", + "查全校信息": "select 字段 from 信息表" +} +``` + +就能自动生成 SQL 了,还可以查看调用关系,非常清晰: + +![](./doc/assets/complex-example-result.png) + ## 实现 diff --git a/doc/assets/complex-example-result.png b/doc/assets/complex-example-result.png new file mode 100644 index 0000000..935a6a1 Binary files /dev/null and b/doc/assets/complex-example-result.png differ diff --git a/doc/assets/complex-example.png b/doc/assets/complex-example.png new file mode 100644 index 0000000..c8018e7 Binary files /dev/null and b/doc/assets/complex-example.png differ diff --git a/src/App.vue b/src/App.vue index 4e226d4..0c92a3a 100644 --- a/src/App.vue +++ b/src/App.vue @@ -59,6 +59,14 @@ const getSQL = () => { console.log(invokeTree.value); }; +const importExampleAndCal = () => { + if (inputEditor.value) { + const exampleJSON = importExample("complex"); + toRaw(inputEditor.value).setValue(exampleJSON); + inputEditor.value.getAction("editor.action.formatDocument").run(); + } +}; + const showInvokeTree = () => { if (!invokeTree.value) { getSQL(); @@ -121,7 +129,7 @@ onMounted(() => { 查看调用树 - + 导入例子 diff --git a/src/examples/complex.json b/src/examples/complex.json new file mode 100644 index 0000000..e043ab0 --- /dev/null +++ b/src/examples/complex.json @@ -0,0 +1,31 @@ +{ + "main": "select (a / b - 1) from (@查整体(date = 今天)) a, (@查整体(date = 昨天)) b", + "查整体": "@查年级() union @查1班() union @查2班() where date = #{date}", + "查年级": "@查汇总_性别汇总() union @查汇总_性别分组() union @查汇总_爱好汇总() union @查汇总_爱好分组() union @查汇总_电脑类别汇总() union @查汇总_电脑类别分组()", + "查汇总_性别汇总": "@查除电脑关联表()", + "查汇总_性别分组": "@查除电脑关联表() group by 性别", + "查汇总_爱好汇总": "@查除电脑关联表()", + "查汇总_爱好分组": "@查除电脑关联表() where 爱好 in (xx) group by 爱好", + "查汇总_电脑类别汇总": "@查除三连和学习表()", + "查汇总_电脑类别分组": "@查除三连和学习表() group by 电脑类别", + "查1班": "@查1班_性别汇总() union @查1班_性别分组() union @查1班_爱好汇总() union @查1班_爱好分组() union @查1班_电脑类别汇总() union @查汇总_电脑类别分组()", + "查1班_性别汇总": "@查除电脑关联表() where 1班", + "查1班_性别分组": "@查除电脑关联表() where 1班 group by 性别", + "查1班_爱好汇总": "@查除电脑关联表() where 1班", + "查1班_爱好分组": "@查除电脑关联表() where 1班 and 爱好 in (xx) group by 爱好", + "查1班_电脑类别汇总": "@查除三连和学习表() where 1班", + "查1班_电脑类别分组": "@查除三连和学习表() where 1班 group by 电脑类别", + "查2班": "@查2班_性别汇总() union @查2班_性别分组() union @查2班_电脑类别汇总() union @查2班_电脑类别分组()", + "查2班_性别汇总": "@查除电脑关联表() where 2班", + "查2班_性别分组": "@查除电脑关联表() where 2班 group by 性别", + "查2班_电脑类别汇总": "@查除三连和学习表() where 2班", + "查2班_电脑类别分组": "@查除三连和学习表() where 2班 group by 电脑类别", + "查所有关联表": "@查信息表() left join (@查三连表()) left join (@查学习表()) left join (@查电脑表()) left join (@查全校信息())", + "查除电脑关联表": "@查信息表() left join (@查三连表()) left join (@查学习表()) left join (@查全校信息())", + "查除三连和学习表": "@查信息表() left join (@查电脑表()) left join (@查全校信息())", + "查信息表": "select 字段 from 信息表 where 年级 = 1", + "查三连表": "select 字段 from 三连表 where 年级 = 1", + "查学习表": "select 字段 from 学习表 where 年级 = 1", + "查电脑表": "select 字段 from 电脑表 where 年级 = 1", + "查全校信息": "select 字段 from 信息表" +} \ No newline at end of file diff --git a/src/examples/index.ts b/src/examples/index.ts index 4c25e74..262305f 100644 --- a/src/examples/index.ts +++ b/src/examples/index.ts @@ -1,7 +1,9 @@ import init from "./init.json"; +import complex from "./complex.json"; const exampleMap: Record = { init, + complex, }; export const importExample = (key: string) => { diff --git a/src/generator/index.ts b/src/generator/index.ts index 5f88c38..aa0f9f0 100644 --- a/src/generator/index.ts +++ b/src/generator/index.ts @@ -92,6 +92,9 @@ function replaceParams( } // 动态、静态参数结合,且优先用静态参数 params = { ...(params ?? {}), ...currentNode.params }; + if (invokeTreeNode) { + invokeTreeNode.params = params; + } // 无需替换 if (!params || Object.keys(params).length < 1) { return sql;