变量使用概述
变量使用概述
变量使用概述
支持使用变量场景列表
- 数据集查询定义
- 数据集维度可选值查询
- 看板参数
- 通用过滤器输入值
- 下拉框默认值
- 权限模板查询语句
- 大屏静态组件Query方式获取数据查询
- 大屏静态组件API方式获取数据URL地址
- 大屏静态文本超链地址
- 大屏图标超链地址
变量的产生
内置变量
| 变量名 | 解释 |
|---|---|
${loginName} | 用户账号: "admin" |
${userName} | 用户名:"超级管理员" |
内置日期变量
内置日期工具cdt,具体使用方法如下:
日期操作
第一个参数用cdt动态生成需要的日期,第二个参数指定日期格式化
-- 当前日期 ${cdt.now(), "yyyy-MM-dd"}
-- 增加一小时 ${cdt.addHour(1), "yyyy-MM-dd"}
-- 增加一天 ${cdt.addDay(1), "yyyy-MM-dd"}
-- 增加一月 ${cdt.addMonth(1), "yyyy-MM-dd"}
-- 增加一周 ${cdt.addWeek(1), "yyyy-MM-dd"}
-- 增加一年 ${cdt.addYear(1), "yyyy-MM-dd"}${}内部使用使用单参数,利用cdt提供的格式换参数format
-- 增加一小时 ${cdt.addHour(1, "yyyy-MM-dd")}
-- 增加一天 ${cdt.addDay(1, "yyyy-MM-dd")}
-- 增加一月 ${cdt.addMonth(1, "yyyy-MM-dd")}
-- 增加一周 ${cdt.addWeek(1, "yyyy-MM-dd")}
-- 增加一年 ${cdt.addYear(1, "yyyy-MM-dd")}指定日期操作
你也可以对指定日期进行操作,
-- 增加一天 ${cdt.addDay("2021-10-30",1, "yyyy-MM-dd")}
-- 增加一月 ${cdt.addMonth("2021-10-30",1, "yyyy-MM-dd")}
-- 增加一周 ${cdt.addWeek("2021-10-30",1, "yyyy-MM-dd")}
-- 增加一年 ${cdt.addYear("2021-10-30",1, "yyyy-MM-dd")}指定日期第一个日期参数支持的日期格式
yyyy/MM/dd HH:mm:ss
yyyy.MM.dd HH:mm:ss
yyyy年MM月dd日 HH时mm分ss秒
yyyy-MM-dd
yyyy/MM/dd
yyyy.MM.dd
HH:mm:ss
HH时mm分ss秒
yyyy-MM-dd HH:mm
yyyy-MM-dd HH:mm:ss.SSS
yyyyMMddHHmmss
yyyyMMddHHmmssSSS
yyyyMMdd
EEE, dd MMM yyyy HH:mm:ss z
EEE MMM dd HH:mm:ss zzz yyyy
yyyy-MM-dd'T'HH:mm:ss'Z'
yyyy-MM-dd'T'HH:mm:ss.SSS'Z'
yyyy-MM-dd'T'HH:mm:ssZ
yyyy-MM-dd'T'HH:mm:ss.SSSZ日期变量支持的起始周期计算
# 指定日期(日期参数类型为日期)对应的年份第一天,格式化为yyyy-MM-dd
${cdt.startOfYear(cdt.addDay(-1), "yyyy-MM-dd")}
# 指定日期(日期参数类型为字符串)对应的年份第一天,格式化为yyyy-MM-dd
${cdt.startOfYear("2023-08-11", "yyyy-MM-dd")}
-- 年份第一天 ${cdt.endOfYear(date, "yyyy-MM-dd")}
-- 年份最后一天 ${cdt.endOfYear(date, "yyyy-MM-dd")}
-- 季度第一天 ${cdt.startOfQuarter(date, "yyyy-MM-dd")}
-- 季度最后一天 ${cdt.endOfQuarter(date, "yyyy-MM-dd")}
-- 月度第一天 ${cdt.startOfMonth(date, "yyyy-MM-dd")}
-- 月度最后一天 ${cdt.endOfMonth(date, "yyyy-MM-dd")}
-- 周第一天 ${cdt.startOfWeek(date, "yyyy-MM-dd")}
-- 周最后一天 ${cdt.endOfWeek(date, "yyyy-MM-dd")}计算日期差
cdt.between("2021-10-30", "2021-11-30", "day")
cdt.between("2021-10-30", "2021-11-30", "hour")
cdt.between("2021-10-30", "2021-11-30", "minute")提示
因为年、月属于不固定时间长度单位所以无法计算时间差
看板参数关联到环境变量

图表联动关联到环境变量

URL参数传递变量
可以通过url参数设定变量所有的url参数都会解析为环境变量, 做看板集成的时候尤为有用
http://localhost:8088/?up=aa&a=%E6%B5%8B%E8%AF%95#/config/cockpit/200326104201751多看板集成-全局变量
url里面的参数为全局参数,在多看板集成场景下会被所有看板继承
http://localhost:8088/render-html.html?a=aa&country=USA多看板集成-局部变量
- 局部变量可以覆盖全局变量
- 局部变量为对象
boards=encodeURIComponent(JSON.stringify(
[
{
showParams: true,
title: '第一个看板',
boardId: 63,
hiddenParamNames: [],
filters: {"boardParams":[{"id":"5chiv3mmalw","name":"国家","type":"=","values":[]}]},
variables: { //这个变量只针对boardId 63
country: 'Mexico'
}
},
{
showParams: true,
title: '第二个看板',
boardId: 64,
hiddenParamNames: ['国家4', '国家3'],
}
]
))变量的使用
数据集中/或者即席查询中
.... 省略其他查询脚本 ...
JOIN foodmart.region r ON c.REGION_ID = r.REGION_ID
JOIN foodmart.customer d ON a.CUSTOMER_ID = d.CUSTOMER_ID
WHERE r.sales_country = '${country}'变量默认值
上面的查询语句中直接使用了自定义变量,但是BI系统如果没有自己在url中传参实际上会出现空值,所以需要给变量一个默认值,让查询在没有传参的场景也能正常运行
.... 省略其他查询脚本 ...
JOIN foodmart.region r ON c.REGION_ID = r.REGION_ID
JOIN foodmart.customer d ON a.CUSTOMER_ID = d.CUSTOMER_ID
WHERE r.sales_country = '${country!"USA"}'数组变量
获取数组变量中的第N个值
当关联到环境变量的参数为数组或者被赋予多个值时,可以通过内置数组udf获取数组中某个元素值,
${arr.get(variable, nth, "defaultValue")} 或者 ${arr.get(variable, nth) ! "defaultValue"}
小技巧
arr.get函数的第一个变量可以为非数组,arr.get("a", 0) 返回值依旧为"a", arr.get("a", 1)为空白
比如现在把日期范围关联到环境变量dt,在查询中可以这样取值
select
....
from
where date_columen between
'${arr.get(dt, 0) ! cdt.addDay(-10,"yyyy-MM-dd")}'
and '${arr.get(dt, 1) ! cdt.addDay(-1,"yyyy-MM-dd")}'也可以用下面的方式在变量没有初始化的情况下设置默认值
${arr.get(dt, 0, cdt.addDay(-1,"yyyy-MM-dd")) }连接数组变量
${arr.joinString(variable, "defaultValues")} ${arr.joinNumber(variable, "defaultValues")}
WHERE SALES_COUNTRY IS NOT NULL
AND r.sales_country in (${arr.joinString(country, "USA, Mexico")})
AND b.month_of_year in (${arr.joinNumber(month, "1, 2, 3,")})
-*/}输出
WHERE SALES_COUNTRY IS NOT NULL
AND r.sales_country in ('USA', 'Mexico')
AND b.month_of_year in (1, 2, 3)案例
逻辑脚本,判断是否存储变量
<%
var where = "where 1 = 1";
if (has(township)) {
where = where + (" AND township = '" + township + "'");
}
if (has(village)) {
where = where + (" AND village = '" + village + "'");
}
if (has(group_name)) {
where = where + (" AND group_name = '" + group_name + "'");
}
%>
select *,1 as cnt from pas_wm_dz_wt ${where}使用条件函数v2.7
cc 对象提供了内置的条件判断函数,可以极大简化传统的 <% %> 脚本块语法。使用 #value 占位符可以引用当前变量的具体值。
select *,1 as cnt from pas_wm_dz_wt
where 1 = 1
${cc.isNotBlank(township, "AND township = '#value'")}
${cc.isNotBlank(village, "AND village = '#value'")}
${cc.isNotBlank(group_name, "AND group_name = '#value'")}cc 函数参考列表
| 函数 | 说明 |
|---|---|
cc.isBlank(val) | 当值为 null 或空字符串时返回 true |
cc.isNotBlank(val) | 当值非空时返回 true |
cc.isBlank(val, then) | 当 val 为空时返回 then 表达式 |
cc.isNotBlank(val, then) | 当 val 非空时返回 then 表达式(支持 #value 占位符) |
cc.isNotBlank(val, then, else) | 根据 val 是否非空分别返回 then / else |
cc.eq(val, target) | 当 val 等于 target 时返回 true |
cc.eq(val, target, then) | 当 val 等于 target 时返回 then 表达式(支持 #value 占位符) |
cc.ne(val, target, then) | 当 val 不等于 target 时返回 then 表达式 |
cc.inList(val, list) | 当 val 存在于 list 列表中时返回 true(支持分号或逗号分隔) |
cc.inList(val, list, then) | 当 val 存在于 list 列表中时返回 then(支持 #value 占位符用于 IN 子句) |
cc.notInList(val, list, then) | 当 val 不存在于 list 列表中时返回 then |
cc.contains(val, substr, then) | 当 val 包含子串 substr 时返回 then |
cc.startsWith(val, prefix, then) | 当 val 以 prefix 前缀开头时返回 then |
cc.endsWith(val, suffix, then) | 当 val 以 suffix 后缀结尾时返回 then |
cc.between(val, min, max, then) | 当 val 在 min 和 max 范围之间时返回 then |
cc.match(val, pattern, then) | 当 val 匹配正则表达式 pattern 时返回 then |
cc.ifNull(val, default) | 当 val 为空时返回默认值 default,否则返回 val 原值 |
cc.coalesce(val1, val2, ...) | 返回第一个非空的值 |
cc.when(condition, then) | 当条件 condition 为 true 时返回 then |
cc.when(condition, then, else) | 根据条件 condition 分别返回 then / else |
三元表达式与 cc 函数结合
-- inList 与三元表达式结合
${cc.inList(name, ['a', 'b', 'c']) ? 'A类' : 'B类'}
-- isNotBlank 与三元表达式结合
${cc.isNotBlank(remark) ? remark : '无备注'}
-- eq 与三元表达式结合
${cc.eq(level, '1') ? 'VIP用户' : '普通用户'}SQL 数组转换函数 — sql
| 函数 | 说明 | 示例 |
|---|---|---|
sql.numberArray(val) | 转换为数值型 IN 列表:(1, 2, 3) | sql.numberArray("1;2;3") → (1, 2, 3) |
sql.stringArray(val) | 转换为字符串型 IN 列表:('a', 'b', 'c') | sql.stringArray("a,b,c") → ('a', 'b', 'c') |
典型使用示例
-- 使用 sql.numberArray 构造动态 IN 条件
${cc.isNotBlank(dept_no, "AND dept_no IN" + sql.numberArray(dept_no))}
-- 输出结果:AND dept_no IN (1, 2, 3)
-- 使用 sql.stringArray 构造动态 IN 条件
${cc.isNotBlank(dept_name, "AND dept_name IN" + sql.stringArray(dept_name))}
-- 输出结果:AND dept_name IN ('A', 'B', 'C')
-- 多值检查与替换
${cc.inList(status, '1;2;3', "AND status IN ('#value')")}
-- 若 status='2',输出:AND status IN ('2')
-- 模板占位符替换
${cc.eq(type, 'A', "type = '#value'")}
-- 若 type='A',输出:type = 'A'
-- 区间计算(常用于条件输出)
SELECT name, age,
${cc.between(age, '18', '60', "'在职'')} as category
FROM employee
-- 若 age='25',输出:'在职'
-- 若 age='65',输出:(空)
-- 正则匹配校验手机号
${cc.match(phone, '^1[3-9]\\d{9}$', "phone_format_valid")}
-- 若 phone='13812345678',输出:phone_format_valid输入格式说明
前端传入的所有变量值均作为字符串处理。多值数组类型的变量可以使用分号 (;) 或逗号 (,) 作为分隔符:例如 "A;B;C" 或 "A,B,C"
查询模板整体替换
判断某个变量是否存在(有值),然后整体替换查询sql,注意的是两个不同的sql需要保证输出的字段一致
<%
var sql;
if (has(country)) {
sql = 'select 1 as c';
} else {
sql = 'select 2 as c';
}
%>
${sql}日期处理
技巧
在<% %>界定符中,通过println函数打印的值会最终输出结果中,可以通过println内容带注释符号,调试模板语法是否正确 println("-- [Log] " + result);
<%
var months = strutil.split(month!"2021-02-01", ",");
var m2 = cdt.add("2021-02-01", 2, -1, "yyyy-MM-dd");
var result = '';
for(m in months){
var monthStr = cdt.addMonth(m, -1, "yyyy-MM-dd");
if (isEmpty(result)) {
result = monthStr;
}
println("-- [Log] " + result);
result = result + ", " + monthStr;
}
%>
select 1 as c
-- ${month}
-- ${result}
Side Effect 副作用
- 对于需要缓存的离线数据集,由于缓存的key为变量赋值之后真实执行查询的语句,当有变量存在的时候会把原来一个数据集保存的数据替换为所有不同变量对应的查询分别缓存;
- 原本执行一次查询,缓存一次,多次读写的数据集需要多次查询、写缓存,可能造成一定的用户体验上高延迟负面影响;
- 变量数据集更加适用于不需要缓存的数据源聚合;