# 数据类型
本文介绍表达式中的数据类型,表达式中的变量、常量、字段等都是有类型的,相比于字段的数据类型,表达式中的数据类型更宽泛一些,如字段类型的字符型和CLOB都会对应表达式中的字符串类型、字段的日期和时间戳都对应表达式中的日期类型,表达式中包括如下类型:
# 数值
数值类型包括整数、浮点数、BigNumber等,数据库中的int、int64、bigint、decimal、numeric、double等在表达式中都是数值类型,表达式中有些函数的参数需要传递整数,如left函数的第二个参数,但传递含有小数的数值也是可以的,在表达式中,各种类型的数值都是可以通用的。
# 数值范围匹配
当需要查找某个指定数值范围内的数据时,可以使用>
、<
等操作符进行数值比较,但也可以使用数值范围匹配来查找对应的数据,示例:
条件 | 说明 |
---|---|
fact.age='18~20' | 表示年龄在18,20之间的数据 ,包含左右两侧边界值,等价于fact.age='[18~20]' 或fact.age>=18 AND fact.age<=20 |
fact.age='[18~20)' | 表示年龄在[18,20)之间的数据 ,[ 表示包含左边界值,) 表示不包含右侧边界值 |
fact.age='18~' | 表示年龄在大于等于18岁的数据 ,等价于fact.age>=18 |
fact.age='(18~)' | 表示年龄在大于18岁以上的数据 ,等价于fact.age>18 |
fact.age='~20' | 表示年龄在小于等于20岁以下的数据 ,等价于fact.age<=20 |
# 多个数值匹配
当需要查找多个指定数值时,可以按照约定的数据项分隔符同时传递多个值进行匹配,示例:
条件 | 说明 |
---|---|
fact.age='18,20' | 表示fact.age IN (18,20) |
fact.age!='18,20' | 表示fact.age NOT IN (18,20) |
fact.age=参数 | 参数包含多值且参数为18,20 ,表示fact.age IN (18,20) |
fact.age=ARR(18,20) | 表示fact.age IN (18,20) |
fact.age=ARR('18,19',20) | 表示fact.age IN (18,19,20) |
# 字符串
在表达式中,字符型字段和CLOB型的字段在表达式中是字符串类型,单引号或双引号括起来的内容都是常量字符串。
# 字符串转义符
单引号或双引号括起来的内容都是常量字符串,如果字符串中有特殊符号如回车换行需要使用转义符来转义,示例:
条件 | 说明 |
---|---|
\r | 回车符 |
\n | 换行符 |
\t | 水平制表 |
\0 | ASCII码0 |
\\ | 代表一个反斜线字符\ |
\' | 代表一个单引号字符' |
\" | 代表一个双引号字符" |
\u+4位16进制数 | 代表指定的Unicode字符,如'\u597d' 代表汉字“好”、'\uD83D\uDE04' 代表表情符号“😄” |
# 字符串通配符
在使用like
或not like
时,系统支持使用通配符,来生成条件,查询期望的数据。
通配符 | 说明 |
---|---|
* 或% | 匹配多个字符,比如:湖北* 表示“湖北”开头 |
? 或_ | 匹配一个字符,比如:*有限??公司 表示结尾是“有限某某公司” |
示例:
条件 | 说明 |
---|---|
fact.[企业名称] like '*科技*' | 匹配企业名称包含科技 |
fact.[企业名称] like '%科技%' | 同上 |
fact.[企业名称] like '湖北*' | 匹配企业名称湖北 开头 |
fact.[企业名称] like '湖北%' | 同上 |
fact.[企业名称] like '*有限??公司' | 匹配企业名称结尾是有限某某公司 |
fact.[企业名称] like '*有限__公司' | 同上 |
# 通配符与转义符
需要查找的数据中含有通配符时,必须使用转义符,才能使查找的通配符具有意义,like默认使用\
转义,需要特别注意的是,字符串常量也是用\
转义,所以在表达式中输入常量的通配符需要使用两个转义符。
条件 | 说明 |
---|---|
fact.[企业名称] like '\\*\\*\\**' | 匹配企业名称*** 开头 |
fact.[企业名称] like '*\\%*' | 匹配企业名称包含% |
fact.[企业名称] like '%\\%%' | 同上 |
fact.[企业名称] like '*\\\\*' | 匹配企业名称包含\ |
# 逻辑匹配
在使用CONTAINS
(包含)关系的条件时,系统支持使用字符串逻辑匹配生成条件,使用空格
、AND
或&
表示逻辑与,用OR
或|
表示逻辑或,具体请参考操作符-数据项分隔符。
如可以使用fact.[企业名称] CONTAINS '加油站|成品油'
查询企业名称里包含加油站
或成品油
的企业,系统会自动将查询条件翻译为fact.[企业名称] like '*加油站*' or fact.[企业名称] like '*成品油*'
。
在以下几种场景支持使用字符串逻辑匹配:
- 在输入表达式过滤条件时,如
fact.[企业名称] CONTAINS '加油站|成品油'
- 在字段筛选组件中,TODO,link下文档
- 在其它条件输入组件中,如在参数栏中放一个输入框input1,使用包含方式匹配输入框绑定的条件字段,此时可以直接在输入框中输入逻辑匹配条件,如
武汉 AND 加油站
更多示例如下:
条件 | 说明 |
---|---|
CONTAINS '武汉 责任' | 表示包含武汉 和责任 ,和CONTAINS '武汉 AND 责任' 等价 |
CONTAINS '武汉 半导体|上海' | 表示包含武汉 和半导体 ,或包含上海 |
CONTAINS '武汉 (半导体|投资)' | 表示包含武汉 ,且含半导体 或投资 |
CONTAINS '武汉 "半导体(含芯片)"' | 表示包含武汉 和半导体(含芯片) ,其中括号是要包含的字符中的普通字符 |
CONTAINS '武汉 "\"半导体\""' | 表示包含武汉 和"半导体" ,其中双引号是要包含的字符中的普通字符 |
CONTAINS ARR('武汉&半导体','上海&投资') | 表示包含武汉 和半导体 或包含上海 和投资 |
"
扩起来的内容,会当一个完整的搜索块使用"
括起的内容里面有"
时,用\
转义
# 维项匹配
数据库中多数的维都有层次关系,比如像产品、地区等,可以通过操作符-数据项分隔符中支持的分隔符来表示多个维项值,同时可以根据操作符左侧是字段还是层次还表示是否包含下级维项,参考逻辑运算符警告提示框的描述说明。
示例:
条件 | 示例 |
---|---|
fact.[区划代码]='420000' | 420000代码表示湖北省,表示包含湖北省(不包含下级) 的数据 |
fact.[区划代码].[省市县层次]='420000' | 420000代码表示湖北省,表示包含湖北省(包含下级) 的数据 |
fact.[区划代码]='420000,430000' | 支持多选,430000表示湖南省,表示包含湖北省(不包含下级)和湖南省(不包含下级) 的数据 |
fact.[区划代码].[省市县层次]='420000,430000' | 支持多选,430000表示湖南省,表示包含湖北省(包含下级)和湖南省(包含下级) 的数据 |
fact.[区划代码] BELONG '420000,430000' | 等价于fact.[区划代码].[默认层次]='420000,430000' ,支持多选,430000表示湖南省,表示包含湖北省(包含下级)和湖南省(包含下级) 的数据 |
fact.[区划代码]="420000|430000" | 同上 |
fact.[标签]="A001&A002" | 标签为A001和A002同时满足。表示and关系的两个值条件,多用于标签条件。 |
fact.[区划代码]!='420000' | 表示不包含湖北省(不包含下级) 的数据 |
fact.[区划代码].[省市县层次]!='420000' | 表示不包含湖北省(包含下级) 的数据,等价于fact.[区划代码] NOT BELONG '420000' |
fact.[区划代码]!='420000,430000' | 表示不包含湖北省(不包含下级)和湖南省(不包含下级) 的数据 |
# 日期
# 相对日期匹配
当需要按照某个锚点日期偏移指定时间间隔过滤时,需要使用相对日期来匹配过滤数据。系统中使用锚点日期关键字+偏移量
的字符串来表示相对日期。
系统中约定的锚点日期关键字有如下几种:
类型 | 说明 |
---|---|
today | 今天,对于一些特殊的数据期类型,如季度,today可以表示当期 |
now | 现在,当前时刻,含有当前日期和时分秒信息,是一个时间戳。now也可以用于和日期或年月进行比较,表示当天、当月或当年 |
current | 本期、本月、本季, 根据当前数据期类型的不同,current表示它的当前一期,如果是退化日期维,那么也就是维中设置当期值,如果当前是日期类型,那么等价于today |
firstPeriod | 首期,往往表示当年的第一期,根据当前数据期类型的不同,如年季,表示当年第一季度 |
lastPeriod | 最后一期,往往表示当年的最后一期,根据当前数据期类型的不同,如年季,表示当年第四季度 |
week1 | 本周第一天,等价于monday |
monday | 本周第一天,等价于week1 |
weekend | 本周最后一天 |
day1 | 本月第一天 |
lastDay | 本月最后一天 |
lastWorkday | 上一个工作日 |
firstDayOfYear | 本年第一天 |
lastDayOfYear | 本年最后一天 |
系统中约定的偏移时间间隔类型有如下几种:
类型 | 说明 |
---|---|
y | 年 |
q | 季 |
m | 月 |
w | 周 |
d | 天 |
wd | 工作日 |
ym | 月,忽略年份 |
yd | 天,忽略年份 |
md | 天,忽略月份 |
示例:
条件 | 说明 |
---|---|
fact.[上映日期]='today' | 表示日期为今天 的数据 |
fact.[上映日期]='-1d' | 表示日期为昨天 的数据 |
fact.[上映日期]='+1d' | 表示日期为明天 的数据 |
fact.[上映日期]='week1' | 表示日期为本周1 的数据 |
fact.[上映日期]='week1-7d' | 表示日期为上周1 的数据 |
fact.[上映日期]='day1-1d' | 表示日期为上月最后1天 的数据 |
fact.[上映日期]='-1m' | 表示日期为上月的今天 的数据 |
fact.[上映日期]='firstDayOfYear' | 表示日期为今年第1天 的数据 |
fact.[上映日期]='lastDayOfYear' | 表示日期为今年最后1天 的数据 |
fact.[上映日期]='week1' | 表示日期为本周1 的数据 |
fact.[上映日期]='-1w' | 表示日期为上周的今天 的数据 |
fact.[上映日期]='-1q' | 表示日期为上季的今天 的数据 |
# 日期范围匹配
当需要查找某个日期范围内的数据时,需要使用日期范围匹配来查询所期望的数据。
示例:
条件 | 说明 |
---|---|
fact.[上映日期].[年]='[2019~2020]' | 表示日期为[20190101~20200101] 之间的数据 |
fact.[上映日期].[年]='[2019~]' | 表示日期为20190101及以后 的数据,等价于>=20190101 |
fact.[上映日期].[年]='[~2020]' | 表示日期为20200101及以前 的数据,等价于<=20200101 |
fact.[上映日期].[年月]='[201901~202008]' | 表示日期为[20190101~20200801] 的数据 |
fact.[上映日期].[年月]='[201902~]' | 表示日期为20190201及以后 的数据,等价于>=20190201 |
fact.[上映日期].[年月]='[~202008]' | 表示日期为20200801及以前 的数据,等价于<=20200801 |
fact.[上映日期].[年月日]='[20190101~20190701]' | 表示日期为[20190101~20190701] 之间的数据 |
fact.[上映日期].[年月日]='[20190101~]' | 表示日期20190101及以后 的数据,等价于 >='20190101' |
fact.[上映日期].[年月日]='[~20190701]' | 表示日期20190701及以前 的数据,等价于 <='20190701' |
fact.[上映日期].[日期]='[20190101 08:30:00~20190701 09:00:00]' | 表示日期为[20190101 08:30:00~20190701 09:00:00] 之间的数据,时间使用24小时制 |
fact.[上映日期]='[09:00:00~12:30:00]' | 表示每天9:00到12:30 的数据,时间使用24小时制 |
fact.[上映日期]='[21:00:00~03:30:00]' | 表示每天21:00到次日凌晨03:30 的数据 |
fact.[上映日期]='[21:00:00~21:00:00]' | 表示每天21:00这一时刻 的数据 |
fact.[上映日期].[年]='['+adddate(year(today()),-3,'y')+'~'+year(today())+']' | 动态区间,表示最近三年 |
fact.[上映日期]='week1-2w~weekend' | 表示日期为前三周 的数据 |
fact.[上映日期]='day1-1m~day1-1d' | 表示日期为上个月的第1天到上个月的最后1天 的数据 |
# 自适应粒度匹配
当字段是日期型、时间戳型或者具有日期角色时,能根据传递的值自适应粒度匹配。
示例:
条件 | 说明 |
---|---|
fact.[上映日期]='[2019~2020]' | 右侧区间范围值是4位,自适应粒度为年 ,左侧字段等价于[上映日期].[年] ,表示[上映日期].[年]='[2019~2020]' |
fact.[上映日期]='2019' | 右侧值是4位,自适应粒度为年 ,左侧字段等价于[上映日期].[年] ,表示[上映日期].[年]='2019' |
fact.[上映日期]='2019,2020' | 右侧是多值,每个值都是4位,自适应粒度为年 ,左侧字段等价于[上映日期].[年] ,表示[上映日期].[年]='2019,2020' |
fact.[上映日期]='[201901~202001]' | 右侧区间范围值是6位,自适应粒度为年月 ,左侧字段等价于[上映日期].[年月] ,表示[上映日期].[年月]='[201901~202001]' |
fact.[上映日期]='201901' | 右侧值是6位,自适应粒度为年月 ,左侧字段等价于[上映日期].[年月] ,表示[上映日期].[年月]='201901' |
fact.[上映日期].[年月]='20190801' | 细粒度值自适应粗粒度字段,左侧字段是年月,右侧是日期,右侧细粒度的值自适应粒度为年月 ,等价于fact.[上映日期].[年月]='201908' |
fact.[上映日期]='201901,202001' | 右侧是多值,每个值是6位,自适应粒度为年月 ,左侧字段等价于[上映日期].[年月] ,表示[上映日期].[年月]='201901,202001' |
fact.[创建时间]='[20190102~20200301]' | 右侧区间范围值是8位,自适应粒度为年月日 ,左侧字段等价于[创建时间].[日期] ,表示[创建时间].[日期]='[20190102~20200301]' |
fact.[创建时间]='20190102' | 右侧值是8位,自适应粒度为年月日 ,左侧字段等价于[创建时间].[日期] ,表示[创建时间].[日期]='20190102' |
fact.[创建时间]='20190102,20200101' | 右侧是多值,每个值是8位,自适应粒度为年月日 ,左侧字段等价于[创建时间].[日期] ,表示[创建时间].[日期]='20190102,20200101' |
fact.[上映日期]='2019,202001' | 右侧是不同粒度的多值,第一个值是4位,自适应粒度为年 ;第二个值是6位,自适应粒度为年月 ,表示[上映日期].[年]='2019' OR [上映日期].[年月]='202001' |
fact.[上映日期].[年]='20190928,202001' | 右侧是不同粗粒度的多值,都自适应粒度为年 ,表示[上映日期].[年]='2019' OR [上映日期].[年]='2020' |
fact.[上映年月]='2019,202001,20180818' | 右侧是不同粒度的多值,既有粗粒度,也有细粒度的值,自适应粒度后表示为fact.[上映年月].[年]='2019' OR fact.[上映年月]='202001' OR fact.[上映年月]=='201808' |
fact.[上映日期].[年月]='week1-2w~weekend' | 按照相对日期计算出来的日期范围进行粒度自适应 |
fact.[上映日期].[年月]='day1-1m~day1-1d' | 按照相对日期计算出来的日期范围进行粒度自适应 |
TIP
日期自适应粒度可以双向自适应:
1、粗粒度值自适应细粒度字段,取细粒度字段相同粒度的维属性过滤,比如:[上映日期]='201802'
自适应为fact.[上映年月].[年月]='201802'
2、细粒度值自适应粗粒度字段,将细粒度值截断,比如:[上映日期].[年月]='20180210'
自适应为[上映日期].[年月]='201802'
# 布尔
布尔值有两个值:真和假,值为真用true
,值为假用false
。也可以使用其他数据类型进行布尔值的转换,如下所示:
数据类型 | 转换结果 |
---|---|
任何非零数字 | true |
0 | false |
任何非空字符串 | true |
""(空字符串) | false |
示例:
条件 | 示例 |
---|---|
if($XSSL,fact.[销售数量]>$XSSL,true) | 表示销售数量为参数中的销售数量时,输出大于该参数的销售数量,否则输出全部销售数量 |
if(fact.[销售数量] IS NOT NULL,[销售数量],0) | 表示销售数量不为空时,输出为销售数量的数据,否则输出0 |
# JSON
表达式支持JSON(JavaScript Object Notation)数据类型,其规范与JavaScript一致,JSON中可能也包括数组,比如JSON中某些key的值可以是数组,但数组也会作为一个独立的数据类型在数组中描述。
系统支持了一系列的JSON表达式函数用于提供操作JSON数据的能力,如JSON_OBJECT、JSON_GET、JSON_SET等等,其中有些函数是适用于数组的,数组函数也是以JSON开头的。在前端浏览器中的表达式计算、后端Java段的表达式函数计算和SQL中均可使用这些JSON函数,但受限于数据库本身的JSON支持能力,部分JSON函数可能在某些数据库无法使用。
# JsonPath
JsonPath是一种描述JSON内部的特定位置的数据的语法,由于JSON是一个结构可以任意复杂的对象,当希望获取或更新JSON中的某个位置的数据时通过JsonPath可以很好的进行表达,以下面的JSON为示例:
{
"store": {
"book": [
{
"category": "reference",
"author": "Nigel Rees",
"title": "Sayings of the Century",
"price": 8.95
},
{
"category": "fiction",
"author": "Herman Melville",
"title": "Moby Dick",
"isbn": "0-553-21311-3",
"price": 8.99
},
{
"category": "fiction",
"author": "J.R.R. Tolkien",
"title": "The Lord of the Rings",
"isbn": "0-395-19395-8",
"price": 22.99
}
],
"bicycle": {
"color": "red",
"price": 19.95
}
},
"expensive": 10
}
示例语法(表达式中以json_data代表上面的示例数据):
表达式 | 结果 |
---|---|
JSON_GET(json_data,'expensive') | 10 |
JSON_GET(json_data,'$.expensive') | 10 |
JSON_GET(json_data,'$.store[1].category') | reference |
JSON_GET(json_data,'$.store[*].author') | ["Nigel Rees","Herman Melville","J.R.R. Tolkien"] |
更多示例请参考:JsonPath (opens new window)
在表达式中可以通过JSON路径语法来表示JSON路径,语法和示例参考:JsonPath (opens new window),以下是支持的操作符:
操作符 | 描述 |
---|---|
$ | 数组、JSON的根元素 |
.property | 选择父对象中的指定属性,此时父对象必须是JSON |
[n] | 从数组中选择第 n 个元素。索引从1开始。 |
[index1,index2,…] | 选择具有指定索引的数组元素 |
[start:end] 、[start:] | 从起始索引到结束索引(但不包括结束索引)选择数组元素。如果省略 end,则选择从开始到数组末尾的所有元素。 |
[:n] | 数组的前 n 个元素 |
[-n:] | 选择数组的最后 n 个元素 |
* | 通配符选择JSON或数组中的所有元素 |
@ | 当前元素的值 |
@# | 当前元素的序号,0开始 |
提示
1、JsonPath的语法规则同样适用于数组、嵌套JSON数组。
2、产品中的路径同时还兼容直接传递数组下标和JSON的KEY。路径是数值表示数组索引下标,是$
开头字符表示JsonPath的路径,非$
开头的字符,则表示是json的key,如果json的key也是以$
开头,则使用\$
转义。
# 数组
数组可以是普通的一维数组、二维数组以及嵌套JSON的数组等,上面的JsonPath语法同样适用于获取数组元素。
示例数据:
[
{
"category": "reference",
"author": "Nigel Rees",
"title": "Sayings of the Century",
"price": 8.95
},
{
"category": "fiction",
"author": "Herman Melville",
"title": "Moby Dick",
"isbn": "0-553-21311-3",
"price": 8.99
},
{
"category": "fiction",
"author": "J.R.R. Tolkien",
"title": "The Lord of the Rings",
"isbn": "0-395-19395-8",
"price": 22.99
}
]
示例语法(表达式中以json_data代表上面的示例数据):
表达式 | 结果 |
---|---|
JSON_GET(json_data, 1) | {"category": "reference","author": "Nigel Rees","title": "Sayings of the Century","price": 8.95} |
JSON_GET(json_data, '$[1]') | {"category": "reference","author": "Nigel Rees","title": "Sayings of the Century","price": 8.95} |
JSON_GET(json_data, '$[2].author') | Herman Melville |
# NULL值
表达式中是存在null值的,null
表示null值、未填写数据的字段和输入框的值也是null,在表达式中null参与的运算规范,不同于sql、也不同于excel,在数据库中null参与的任何运算返回的都是null、文本字段中存储null和空字符串也不同,而在excel中没有null的概念,单元格没填写内容就认为是空。
在表达式中null参与的运算有一些特殊的规则,我们希望在大多数情况下使用者不需要特殊处理null,但有些极端情况下可能还是需要识别是不是null的,比如我们的表达式中就有isnull
这个运算符,这可以让系统在翻译对应的SQL语句时自动产生条件字段 is null
或字段=''
,另外由于null在db中参与任何四则运算都是返回null,比如null+1
返回null,但其实更希望它返回1,系统会在产生SQL的时候自动应对这些情况,多数情况下都能做到符合用户的预期,在少数情况下,用户也能通过写入一些特定的规则的表达式语法或其他方式能做到一些特殊的计算规则。
在表达式中规则如下:
- null当字符串使用时等价于空字符串,如
null=''
返回true,null+'abc'
返回'abc',字段=''
在翻译SQL时为字段 is null
。 ==
、is null
和is not null
是用于严格对待null的判断,不同于其他操作符,如'' is null
返回false,null==''
返回false,''=null
还是返回true。- =、!=、>、>=、<、<=、in、like、contains等比较运算符,如果是和字符串进行比较,null和''等价,null和null用=比较是相等的,其他操作数(不管是否null)和null比较的都返回false。
- null在四则运算中,包括加减乘除、AVG、SUM等,如果操作数都是null,那么返回null。
- null在加法中(包括SUM)被忽略,如
null+1
返回1,null+null
返回null,字段+1
在翻译SQL时会翻译为ifnull(字段,0)+1
。 - null在减法中当0处理,如
null-1
返回-1,null-null
返回null,字段-1
在翻译SQL时为字段-1
。 - 在乘法、除法中,如果有一个操作数为null,那么结果为null
- null当作布尔值时是false,
null&true
返回false,!null
返回true,if(null,1,2)
返回2,null=false
返回true,null==false
返回false。
在系统产生的SQL中,除了符合上面的表达式计算规则外,还有如下规则:
- 不管底层数据库字段存储是否支持区分对待null和空串,系统在提交数据到DB时,''会转化为null,也就是说不会往字符串字段中写入空串。
- 在查询时,如果用户过滤条件写
字段=''
,那么翻译为SQL时为字段 is null
,考虑到性能和SQL简洁性,系统不会自动加上or 字段=''
,如果用户的db中存在历史数据有区分对待null和'',那么用户需要显式的写条件字段==''
才能做严格的空串比较 - 字段作!=、<>、>、<等比较时,如果是和字符串比较,那么按上面表达式的规则null等价于'',其他情况,如果比较数是null,那么非null值大于null、非null也不等于null,如果比较数不是null,那么直接比较即可。
- 万一用户不希望系统在翻译SQL时自动处理null的问题,比如希望
字段+null
时,就严格按字面翻译SQL,那么可以使用RAW_SQL
系列函数。 - null值不参与SQL的count统计计数,这个和SQL一致。