不止like和in:cj2sql扩展SQL关键字全清单,between、exists、caseWhen一次讲透
【免费下载链接】cj2sql将仓颉代码转换成 SQL项目地址: https://gitcode.com/Cangjie-SIG/cj2sql
cj2sql 是一个将仓颉代码转换成 SQL 的开源工具,而它的扩展 SQL 关键字是最让新手上头的功能:用仓颉函数调用的方式写出between、exists、caseWhen、like、in等 SQL 条件,编译期自动展开成标准 SQL,免去手工拼接字符串的痛苦。🚀
一、cj2sql 扩展 SQL 关键字全清单
cj2sql 通过枚举ExtSql声明所有扩展 SQL 关键字(定义见 src/sql/use.cj),完整清单如下:
| 关键字 | 作用 | 生成的 SQL |
|---|---|---|
like/notLike | 原生模糊匹配 | col LIKE 'abc' |
likeLeft/likeRight/likeAll | 左/右/全模糊 | col LIKE 'abc%'等 |
notLikeLeft/notLikeRight/notLikeAll | 反向模糊 | col NOT LIKE ... |
inn/notIn | 列表包含 | col IN (1, 2, 3) |
between/notBetween | 区间判断 | col BETWEEN 1 AND 5 |
exists/notExists | 子查询存在性 | EXISTS (SELECT ...) |
caseWhen | 条件表达式 | CASE WHEN ... END |
null/notNull | 判空(配合is) | col IS NULL |
asc/desc | 排序方向(配合is) | col ASC / DESC |
not | 逻辑非 | NOT (expr) |
二、两步上手:导入 + 声明
使用规则非常简单:ExtSql.关键字(参数列表),前缀ExtSql.可以省略。
import cj2sql.macros.cjSql // 宏 import cj2sql.sql.ExtSql // 扩展 SQL 关键字 import cj2sql.sql.select只需给函数标注@cjSql宏,函数体内的 DML 代码就会在编译期被解析、展开成 SQL。整个解析流程可以这样理解:
其中「扩展关键字」就是由CallExprParser分发给BaseCallExtKeyParser系列解析器完成的(参见 src/macros/parser/call_ext_keyword_parser.cj)。
三、between:区间条件怎么写
规则:between(列, 开始值, 结束值),反向用notBetween。
let five = 5 between(user.id, 1, five) // ==> user.id BETWEEN 1 AND ?参数支持字面量或变量,变量会被生成为绑定参数?,天然防止 SQL 注入。解析逻辑见 call_ext_key_between_parser.cj,参数个数不对时会在编译期直接报错,非常省心。
四、exists:子查询存在性判断
规则:exists(子查询),反向用notExists。
exists(user.subQuery<RoleTest> { r => r.select { r.id }.filter { r.id == 2 } }) // ==> EXISTS (SELECT r.id FROM role_test r WHERE r.id = 2)「查主表 + 判断关联表里是否存在记录」这类常见需求,一行exists就搞定,不用手写嵌套查询字符串。解析器在 call_ext_key_exists_parser.cj。
五、caseWhen:把 if/match 直接变 CASE WHEN
规则:caseWhen(if或match表达式),可用作 select 列(需配合as)。
caseWhen(if (user.id > 1) { user.id } else { user.roleId }) == 1 // ==> (CASE WHEN user.id > 1 THEN user.id ELSE user.role_id END) = 1写法很巧妙:仓颉里的if/else和match表达式会一一映射成 SQL 的WHEN/THEN/ELSE,多级else if也支持,解析实现见 call_ext_key_case_parser.cj。
六、like 与 in:不只是简单匹配
除了原生like,cj2sql 还提供了likeLeft/likeRight/likeAll三种模糊匹配,无需手动拼%:
likeRight(user.name, 'cang') // ==> user.name LIKE 'cang%' likeAll(user.name, 'jie') // ==> user.name LIKE '%jie%' inn(user.id, 1, 2, 3) // ==> user.id IN (1, 2, 3)inn还支持传入数组变量,甚至直接传入子查询:
let list = [10, 20, 30] inn(user.id, list) // ==> user.id IN (?, ?, ?)七、null / notNull / asc / desc:用 is 关键字
这四个关键字配合仓颉的is语法使用,读起来和原生 SQL 几乎一致:
user.id is null // ==> user.id IS NULL user.id is notNull // ==> user.id IS NOT NULL user.roleId is desc // ==> user.role_id DESC八、底层原理:一切皆语法树节点
每个扩展关键字最终都会转成 SQL 语法树中的表达式节点(如SqlBetweenExpr、SqlExists、SqlCaseExpr),再经方言层渲染成 MySQL / Oracle / PostgreSQL / SQLServer 的具体 SQL,结构可参考官方设计文档 doc/design.md:
表达式节点源码集中在 src/sql/expr/,工具方法见 ExprUtil。
九、总结
cj2sql 的扩展 SQL 关键字让「写 SQL」变成了「写仓颉」:
- ✅清单全覆盖:like 家族、in、between、exists、caseWhen、判空与排序一次配齐
- ✅编译期展开:参数错误在编译阶段就报错,运行零风险
- ✅多数据库方言:同一份代码可渲染多种数据库 SQL
更多实战示例(增删改查全流程)可直接阅读 doc/use.md,跟着文档走一遍即可上手。
【免费下载链接】cj2sql将仓颉代码转换成 SQL项目地址: https://gitcode.com/Cangjie-SIG/cj2sql
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考