sybn sybn-util 项目说明文档 - 基于java的跨数据库联合查询

sybn sql 执行模型与命令分类总览

2026-06-15
sybn
sql

  • content

概述

sybn sql 是基于 SQL-92 扩展的多语句流水线查询语言。它在标准 SQL 基础上增加了三类能力:

  1. 流水线——多条语句用分号 ; 连接,前一条的结果自动传递给后一条。
  2. 非标命令——20+ 个扩展命令,覆盖列操作、行列转换、批量执行、缓存、调试等场景。
  3. 异构数据源——可在一条 SQL 中联合查询 mysql、mongo、es、redis、json、csv 等。

本文是 sybn sql 的执行模型总览,适合作为 nl2sql(自然语言转 SQL)应用的命令选择参考。


一、流水线执行模型

1.1 分号多语句

sybn sql 用分号 ; 连接多条语句,按顺序执行:

select * from users where age > 18;
appendColumns(now() as query_time);
removeColumns(password);

执行流程:

  1. 第一条 select 查询用户表,结果压入堆栈。
  2. 第二条 appendColumns 从堆栈取出结果,追加 query_time 列,新结果压栈。
  3. 第三条 removeColumns 从堆栈取出结果,删除 password 列,新结果压栈。
  4. 最终返回栈顶结果。

1.1.1 流水线承接规则(重要)

流水线只有最后一个语句的结果会返回,且多语句之间必须有承接关系——后一条语句必须能消费前一条压栈的结果。每条命令对堆栈有明确的「消费量 / 生产量」(见 1.2 节分类):

写法 是否合法 说明
select ...; appendColumns(...) ✅ convert 消费 1 个 source 结果
select ...; removeColumns(...); pivot(...) ✅ 多个 convert 串联
select ...; execBatch(子sql) on ... ✅ execBatch 消费 1 个 source 作为输入列表
select A; select B; left join ... ✅ join 消费 2 个 source,是「两个 select」唯一合法的用法
select 1; select 2 ❌ 两个独立 select 串联,无命令消费,会报错
select ...; select ... from @sybn_last_select@table ⚠️ 变量承接在此环境可能失败
select ...; clearQueue(); select ... ✅ clearQueue 清栈后可重新 select

多步骤查询的正确写法:用一条 select + 子查询 + 转换命令组合。如果需要合并两个独立查询结果,用 join(而不是串联两个 select)。如果确实需要分步,用 execBatch 或 cacheResult 承接。

1.2 堆栈机制

每条语句执行后,结果会被压入一个 stackData 堆栈:

语句1: select ...     →  压栈 [结果1]
语句2: appendColumns  →  弹出[结果1], 处理后压栈 [结果2]
语句3: removeColumns  →  弹出[结果2], 处理后压栈 [结果3]
                                   ↑ 最终返回
  • 默认返回栈顶(最后一条语句的结果)。
  • return 命令可以指定返回堆栈中的任意一层。
  • clearQueue 命令可以清空堆栈。

1.3 命令的流水线行为分类(核心)

每条命令对 stackData 堆栈有明确的「消费量 / 生产量」,这是判断能否承接的依据(对应源码 SySqlCommandConverExecutor.getConsumed()):

分类 消费栈顶 压栈 命令 注入变量
source(产生数据) 0 1 select、union all/union、intersect/except、with as、execBatch(子sql)、dynamicSourceQuery、cacheResult @sybn_last_select@table
convert(转换栈顶) 1 1 appendColumns、prependColumns、removeColumns、alignColumns、splitColumns、builderInsert、pivot、unwind、unnest、fill @sybn_last_conver@table
multi-input(多输入转换) 2 1 INNER/LEFT/RIGHT/FULL JOIN、lookup @sybn_last_join@table
stack-control(清栈) N 或全部 0 clearQueue([N]) —
control-flow(控制流) 0 0 return、if exists、explain —
auxiliary(辅助) 0 0 set @var、show tables/databases/functions、desc、show value stat —
peek(旁路输出) 0 0 peekResult —

消费量来自源码:ConvertSySqlJoin.getConsumed()=2、SySqlExecBatchQueryExecutor.getConsumed()=1、SySqlClearQueueQueryExecutor.getConsumed()=Integer.MAX_VALUE,convert 类命令通过 SySqlCommandConverExecutor 接口默认消费 1 个。

1.4 子查询嵌套:() 包裹多语句流水线

核心模式:用 () 包裹一个多语句流水线,外层可以接标准 SQL 操作(where / group by / order by / having / limit 等),把流水线结果当作一张表来用。

/* 把用户表和订单 join 后, 外层再按城市分组聚合 */
select city, sum(total) as city_total
from (
  /* 第1步: 左表 */
  select id, name, city from users where status = 1;
  /* 第2步: 右表 */
  select user_id, sum(amount) as total from orders group by user_id;
  /* 第3步: join 消费栈顶2个, 输出1个 */
  left join select(name, city, total) on left.id = right.user_id
) where total > 100          /* 外层过滤 */
group by city                /* 外层分组 */
order by city_total desc     /* 外层排序 */
limit 10;

关键规则:

  1. () 内部是独立流水线,有自己的堆栈,内部多语句必须有承接关系(source → convert/multi-input)。
  2. () 内部最终返回栈顶,作为外层 from 的数据源。
  3. 外层可以接任意标准 SQL 子句:where / group by / having / order by / limit / join 等。
  4. () 内部两个独立 select 串联会报错(select 1; select 2 无承接),必须用 join 或转换命令承接。

适用场景:多步骤处理(join/转换)后还需要用标准 SQL 做聚合、过滤、排序时,用 () 包裹流水线,外层写标准 SQL。这比把所有逻辑塞进流水线更清晰。

嵌套层级:() 可以多层嵌套,每层都是独立流水线:

select * from (
  select * from (
    select ...;
    select ...;
    join ...
  ) where ...               /* 内层流水线 + 外层过滤 */
  group by ...
) where ...                  /* 外层再过滤 */
order by ...

二、命令分类体系

sybn sql 的命令分为 7 大类,nl2sql 时根据意图选择。分类按功能划分;按流水线行为(source/convert/multi-input)划分见 1.3 节。

2.1 查询类(DQL,source)

标准 SQL 查询,产生新数据压栈。from 子句支持多种数据源(库表 + 字面量)。

标准库表查询:

命令 语法 用途
select select ... from 库.表 where ... 基础查询
union / union all select ... union all select ... 联合(去重/不去重)
intersect / except select ... intersect select ... 交集/差集
with as with t as (select ...) select * from t CTE 临时表

内联字面量数据源(无需查库,数据写在 SQL 里,源码 TableLoader.loadList()):

数据源 语法 示例
JSON 数组 from [{...},{...}] select * from [{a:1,b:1},{a:2,b:2}]
引号 JSON from "[{...}]" select * from "[{a:1},{a:2}]"
CSV 文本块 from csv(三反引号包裹的CSV文本) select * from csv(三反引号 name,age 换行 张三,20 三反引号)`
TSV 文本块 from tsv(三反引号包裹的TSV文本) select * from tsv(三反引号 name\tage 换行 张三\t20 三反引号)`
VALUES from (VALUES (...),(...)) AS t(列) from (VALUES ("v1"),("v2")) AS t(code)
factory from factory({engine:'...',...}) factory({engine:'timeScope', key:'date', timeScope:'2026-01-01~2026-01-07'})
generate_series from generate_series(1, 10) as a 生成 1-10 整数序列

CSV/TSV 用三反引号文本块包裹,第一行表头(列名),其后数据行。详见 from factory 和 web-sql part2。

跨轮次对话数据合并:把上一轮查询结果手动复制为 JSON/CSV 字面量嵌入当前 SQL,用 join 或 union 合并(详见 from-factory 文档)。

/* 本轮数据 union 上一轮结果(JSON字面量) */
select '本轮' as round, cinema_name, amount from orders where date = curdate()
union all
select '上轮' as round, cinema_name, amount
from [{cinema_name:"影城A", amount:1200}, {cinema_name:"影城B", amount:980}]

2.2 转换类(convert,后置命令)

作用于前一条语句的结果,消费栈顶 1 个,转换后压栈 1 个。不改变行数(除 unwind/unnest)。

命令 用途 改变行数
appendColumns 结尾追加列 否
prependColumns 开头插入列 否
removeColumns 删除列(可按空值条件) 否
alignColumns 对齐/筛选列 否
splitColumns 拆分列为多列 否
builderInsert 结果转 INSERT 语句 否
pivot 行转列 否
unwind 数组/Map 拆成多行(可多字段) 是
unnest 数组/Map 拆成多行(自定义列名) 是
fill 按维度补齐缺失数据行 是

2.3 join 类(multi-input,后置命令)

消费栈顶 2 个(左表 + 右表),join 后输出 1 个结果压栈。前面必须有 2 条 source 语句。源码:ConvertSySqlJoin.getConsumed()=2。

命令 语法 用途
INNER JOIN INNER JOIN SELECT(字段) ON left.x = right.y 内连接
LEFT JOIN LEFT JOIN SELECT(字段) ON left.x = right.y 左连接
RIGHT JOIN RIGHT JOIN SELECT(字段) ON left.x = right.y 右连接
FULL JOIN FULL JOIN SELECT(字段) ON left.x = right.y 全连接
lookup lookup SELECT(字段) ON left.x = right.y mongo 风格 join

示例:

/* 将用户表和订单表 join 起来 */
select * from (
  select id, name from users;
  select user_id, sum(amount) as total from orders group by user_id;
  left join select(name, total) on left.id = right.user_id
) order by total desc

语法说明:

  • SELECT(...):指定返回字段,支持 as 别名和 udf 函数;左右表同名字段优先返回左表值
  • ON:支持 left.x = right.y、x = y、using(字段);多条件用 AND 连接
  • 报错信息:join 需要2张前表,而不是N张.可能是前面的某行代码少写了分号.
  • 详见 DatasSqlJoinUtil

2.4 后置过滤类

作用于子查询结果,语法比嵌套 select 更简洁。

命令 语法 用途
where from (...) where 条件 过滤
order by from (...) order by 字段 desc 排序
limit from (...) limit N 分页

三者可组合:from (...) where 条件 order by 字段 limit N

2.5 子查询执行类(source / 旁路)

执行一个子 SQL,把结果压栈。常用于批量、动态数据源、缓存。

命令 用途 流水线行为
execBatch 批量执行子任务,支持并发/忽略错误 消费栈顶1个作为 @item 列表,压栈1个
dynamicSourceQuery 动态切换数据源执行子查询 source,压栈1个
cacheResult 缓存子查询结果,跨语句复用 source,压栈1个
peekResult 提前输出中间结果到前端/日志 peek,旁路不压栈

2.6 控制流类(control-flow / stack-control)

控制流水线的执行流程。不产生数据。

命令 语法 用途 流水线行为
return return [N / select ...] 提前返回并终止后续 不消费栈不压栈
if exists if exists (select ...) then ... 条件执行 不消费栈不压栈
clearQueue clearQueue([N]) 清理堆栈 消费 N 个或全部
explain explain select ... 查看查询计划(仅 JDBC) 不消费栈不压栈

2.7 辅助类(auxiliary)

不产生数据,用于变量、表结构查看。

命令 用途
set @var := 值 设置变量
use 数据库 切换数据库
show tables / show databases 查看表/库
show create table / desc 表 查看表结构
show functions 查看所有函数
show value stat 查看字段统计特征

三、@变量传递机制

sybn sql 支持 5 种变量,是流水线语句间数据传递的核心:

3.1 特殊上下文变量(自动注入)

这些变量由系统自动注入,引用堆栈中的历史结果:

变量 含义 注入时机
@sybn_last_select@table 最后一个 select 的结果 每次 select 执行后
@sybn_last_conver@table 最后一个转换命令的结果 appendColumns/removeColumns 等执行后
@sybn_last_join@table 最后一个 join 的结果 join 执行后
select * from users;
select count(*) as cnt from @sybn_last_select@table;
/* @sybn_last_select@table 被替换为上一条 select 的结果 */

3.2 用户变量(set 赋值)

set @t := str_to_date('2026-01-01', '%Y-%m-%d');
select * from orders where create_time > @t;
  • 兼容 := 和 = 赋值。
  • 一般只能替换 where 右侧的值。

3.3 列表变量

set @types@list := (select type from config where enabled = 1);
select * from orders where type in (@types@list);
  • @var@list 用于 in 查询传值。
  • 把子查询结果展开为列表。

3.4 外部参数(mybatis 风格)

select * from users where name = ${name} and age > ${age}
  • ${var} 由 sql 外部传入,可替换任意位置。
  • #{var} 同样支持(预编译占位)。

3.5 全局变量

select * from ${${env}_table}
  • $${var} 引用全局变量,可替换任意位置。

四、执行顺序图解

┌─────────────────────────────────────────────────────────┐
│  输入: 多语句 SQL(分号分隔)                              │
└──────────────────────┬──────────────────────────────────┘
                       ↓
            ┌──────────────────────┐
            │  语句1: select ...   │ → 压栈 → 注入 @sybn_last_select@table
            └──────────┬───────────┘      (source: 消费0 压栈1)
                       ↓
            ┌──────────────────────┐
            │  语句2: 转换命令      │ → 弹栈1个处理 → 压栈 → 注入 @sybn_last_conver@table
            │  (appendColumns等)   │      (convert: 消费1 压栈1)
            └──────────┬───────────┘
                       ↓
            ┌──────────────────────┐
            │  语句3: join          │ → 弹栈2个(左+右) → join → 压栈 → 注入 @sybn_last_join@table
            │  (left join 等)      │      (multi-input: 消费2 压栈1)
            └──────────┬───────────┘
                       ↓
            ┌──────────────────────┐
            │  语句4: 子查询命令    │ → 执行子SQL → 压栈
            │  (execBatch等)       │      (source: 消费0/1 压栈1)
            └──────────┬───────────┘
                       ↓
            ┌──────────────────────┐
            │  语句N: return        │ → 指定返回栈中某层
            └──────────┬───────────┘      (control-flow: 不消费不压栈)
                       ↓
                 返回最终结果

五、nl2sql 命令选择指南

自然语言转 SQL 时,按用户意图映射命令:

用户意图 推荐命令 示例自然语言
查询数据 select “查出所有成年用户”
合并两个查询结果 INNER/LEFT/RIGHT/FULL JOIN “把用户表和订单表按用户id关联”
mongo 数据关联 lookup “把 mongo 用户表和订单表关联”
追加计算列 appendColumns “加一列显示年龄是否大于60”
删除敏感列 removeColumns “去掉密码和手机号列”
行转列 pivot “把按月份的行数据转成列”
列转行 unwind / unnest “把 tags 数组拆成多行”
补齐缺失日期 fill “把缺少的日期补上空行”
批量执行 execBatch “对每个用户分别查询订单”
跨库查询 dynamicSourceQuery “从另一个 mysql 库查数据”
缓存慢查询 cacheResult “这个结果缓存一下复用”
条件执行 if exists “如果表存在就查询”
提前返回 return “拿到结果就停止”
数据脱敏 masking() 函数 “手机号中间4位打星号”

六、相关文档

命令详解

内联数据源

基础规范


Comments

暂不开放评论! 可微信联系