外部数据库

外部数据库是由开发者添加进平台的,通常是现存的业务数据库,支撑着当前运行中的业务系统(如ERP),通过SQL语言把平台上新开发的应用与现存系统相融合,从而避免信息孤岛。
如果数据交互量很大,可以考虑把平台私有部署到外部数据库同一个区域以加快数据交换的速度(用内网IP连接效果最佳)。如果无需业务数据的融合则优先考虑直接使用平台内部的Postgres数据库,从而可以利用平台提供的便利的数据查询/操作函数而无须写SQL。
目前支持的外部数据库有PostgreSQL,MySQL,MS SQL Server,Oracle。不限数量。

添加数据库

在设置中心的【外部数据】栏中【+数据库】,在表单中给此数据库起个简单好记的唯一名,并填写连接数据库必要的信息。可用点【测试连接】检查是否能连接得上。

在后端服务中可以通过$sql.数据库名(SQL语句, 参数值)来调用。

查看数据

点击左侧导航栏的【数据表】可以获取数据库的所有数据表并查询其中的数据。

添加SQL

点击【+SQL】添加SQL语句并起个简单好记的唯一名,不同数据库下的SQL也不能重名。此SQL可以在前端直接调用也可以在后端服务中调用:$sql.SQL名(参数值, 选项)

SQL方言

不同数据库的SQL的写法会有所不同,必须按照你所选的数据库的语法来写SQL。比如:

参数占位符

Postgres用$数字作为占位符:UPDATE 商品 SET 价格 = $2 WHERE id = $1
MySQL用?作为占位符:UPDATE 商品 SET 价格 = ? WHERE id = ?
SQL Server用@变量作为占位符:UPDATE 商品 SET 价格 = @价格 WHERE id = @id
Oracle用:变量作为占位符:UPDATE 商品 SET 价格 = :价格 WHERE id = :id

翻页查询

Postgres和MySQL用LIMITSELECT * FROM 商品 ORDER BY id LIMIT 50 OFFSET 25
SQL Server和Oracle用FETCH NEXTSELECT * FROM 商品 ORDER BY id OFFSET 25 ROWS FETCH NEXT 50 ROWS ONLY

参数值

从上面的SQL方言可以推断:Postgres和MySQL需要数组类型的参数值与对应的占位符相匹配,Postgres的参数数组的下标+1对应占位符的数字,MySQL的参数数组的下标对应占位符所在语句中的顺序;SQL Server和Oracle需要对象类型的参数值与对应参数名的占位符相匹配。

占位选项

平台提供的占位选项让SQL更加动态灵活的同时还能保证安全。
占位符用大括号包裹并置于SQL语句的合适位置,并在下方的选项设置框中用数组罗列所有允许的占位值。执行SQL时在选项参数中指定需要用到的占位名称(及占位选项的下标和值)。从上面参数占位符可以看到Postgres的参数是从1开始的,所以约定所有占位选项的下标也是从1开始的。

选择字段{select}占位,比如允许全选也可以只选日期/名称/价格,选项设置框中则写{ select: ["*", "日期", "名称", "价格"] };如果调用时的选项参数传入{ select: [1] }那么{select}就会被替换成SELECT *,如果传入{ select: [2, 4] }那么{select}就会被替换成SELECT 日期, 价格

查询条件{where}占位,选项设置中还可以用??占位。比如根据给定的日期区间和名称模糊查询,选项框中则写{ where: ["日期 >= ??", "日期 <= ??", "名称 LIKE ??"] };调用时传入{ where: { 1: "2024-03-01", 2: "2024-03-31", 3: "%手机%" },那么{where}就会被替换成符合相应数据库语法的预编译语句,如Postgres的WHERE 日期 >= $1 AND 日期 <= $2 AND 名称 LIKE $3和参数值["2024-03-01", "2024-03-31", "%手机%"]

排序{sort}占位,比如按日期和价格排序,选项设置中则写{ sort: ["日期", "价格"] };如果调用时的选项参数传入{ sort: [1] }那么{sort}就会被替换成ORDER BY 日期,即按日期升序排序;如果传入{ sort: [2, -1] }那么{sort}就会被替换成ORDER BY 价格, 日期 DESC,即先按价格升序排序再按日期降序排序。

翻页使用{limit}{skip},无需预先设置选项直接数字参数,调用时传入{ limit: 25, skip: 50 }就是每页25条返回第三页(跳过了两页)。但要注意SQL Server或Oracle需要搭配{sort},并把{skip}放在{limit}前面。

插入使用{insert},无需预先设置选项直接传入对象参数,比如传入{ 日期: "2024-03-01", 价格: 50 }会把{insert}替换成符合相应数据库语法的预编译语句,如Postgres的(日期, 价格) VALUES($1, $2)和参数值["2024-03-01", 50]

更新使用{set},比如只允许更新日期/名称/价格,选项设置框中则写{ set: ["日期", "名称", "价格"] },如果传入{ 日期: "2024-03-01", 价格: 50 }会把{set}替换成符合相应数据库语法的预编译语句,如Postgres的SET 日期 = $1, 价格 = $2和参数值["2024-03-01", 50]

{select},{set},{where}可以和静态语句混用,如SELECT id {select}UPDATE 商品 SET 更新时间 = $1 {set}WHERE 账套 = $1 AND 日期 = $2 {where}

自定义占位符:要求先在选项设置许可数组,调用时在选项参数中传入一个数字下标(从1开始)以指定许可数组中的一项。比如想让【从哪个表查数据】动态化,可以定义一个{table}占位符,写个名为【超级查询】的SQL:SELECT * FROM {table} LIMIT 50,允许从三个表中选一个:{ table: ["商品", "价格", "商家"] },调用$sql.超级查询([], { table: 2 }),将获取价格表的前50条数据。

值的字符串化

如果使用了JSON类型的字段就经常要对参数值进行字符串化JSON.stringify()再传给SQL执行。可以在选项设置框中把需要字符串化值写在str对象中。

比如财务系统中根据指定账套/期间/凭证字【查凭证】:SELECT * FROM 凭证 WHERE x['账套'] = $1 {where},选项设置{ str: { V: [1], where: [1, 2] }, where: ["x['期间'] = ??", "x['字'] = ??"] },执行$sql.查凭证(["众触科技"], { where: { 1: "2024-03", 2: "记" }),将得到SQLSELECT * FROM 凭证 WHERE x['账套'] = $1 AND x['期间'] = $2 AND x['字'] = $3和参数值['"众触科技"', '"2024-03"', '"记"']

SQL约定

通常一个查询语句返回的是一个对象数组,但如果SQL里明确指明只查一条数据时(含有LIMIT 1TOP 1)则只返回第一条数据。

如果是数据操作语句(以INSERT/UPDATE/DELETE开头),则只返回结果数组中的第一条数据。

如果对象数组里只有一条数据且此对象只有一个键且它的值还是个数字,那将只返回此数字。通常是COUNT语句。

如果一个查询语句带有{limit}占位符,将得到一个复合对象:{ arr: 最新查询得到对象数组,all: 多次查询得到的对象数组的合集,count: 所有符合条件的数据条数,skip: 最新查询跳过的条数,skips: 多次查询跳过的条数数组,Q: 最新查询条件,O: 最新设置选项,V: 参数值,find: 快捷再查询函数,传入新的Q和O会与旧的Q和O合并后再次发起查询,如果O未传入则默认是{ skip: 0 },用于翻页时特别方便 }

日志

平台自动为开发模式下的SQL执行开启日志,可以查看每次执行前被替换后的预编译语句和对应的值。

缓存

事务

在后端自定义服务中可以点击【事务】开关以开启事务,开启后这个服务中所有函数都处于事务状态中,其中任一条表达式出错就会停止执行并回滚事务,然后执行回滚表达式并把返回值返回前端,如果没有回滚表达式则会把错误信息返回前端。

在自定义服务中也可以根据条件主动执行rollback()回滚事务,比如如果上一条SQL虽然执行成功但它的执行结果不符合预期,或者先主动查询数据库看看数据是否符合条件,不符合则趁早回滚。

权限/安全

外部数据库里添加的SQL虽然可以在前端直接调用,但本质上依然是个后端服务$sql.name(),有执行前/后两个触发器,可以在真正执行SQL前先执行自定义逻辑以判断权限或者修正参数,执行SQL后还可以执行自定义逻辑,转换最终返回前端的数据或日志处理等任务。具体文档请参考接口安全

由众触低代码平台生成和驱动