# **QUERY**

从数据集查询满足条件的一个或多个数据。

query函数常用于独立灵活的取数计算、[明细填报中取汇总指标数据](##detail-agg)、[跨表数据校验](##cross-check)、[复杂统计分析计算](##complex-statistics)、[动态数据范围权限控制](##dynamic-ds-auth)等场景，能够灵活地从数据集中查询并返回满足条件的数据。

## 语法{#grammar}

QUERY(**exp**, **condition**)

- **exp**：必需，查询表达式，通常是一个引用数据集字段的表达式。可以根据表达式内容返回单个值、一维数组或二维数组等，具体请参考[示例](#example)。
- **condition**： 可选，数据集的查询过滤条件，可以关联其他表进行过滤。

**示例地址：** [QUERY](https://demo.succbi.com/v5/bi/query)

## 示例{#example}

1. 返回一个值

没有使用ARR函数、聚合函数时，默认总是返回查询结果的第一条数据的值。

比如查询满足`[企业基本信息].[经营状态]='存续'`条件的第一条数据的企业名称：`IF(QUERY([企业基本信息].[企业名称],[企业基本信息].[经营状态]='存续') IS NOT NULL,TRUE,FALSE)`

2. 返回一维数组

使用[ARR函数](../json/ARR.md)将多行查询结果转为一维数组返回。

比如查询过滤我关注的用户的信息：`[用户表].[用户ID] IN QUERY(ARR([用户信息].[用户ID]),[用户关注表].[关注人]=$user.id)`

3. 返回二维数组

使用[ARR函数](../json/ARR.md)查询多个字段时将多行查询结果转为二维数组返回。

比如查询满足条件的客户信息：`QUERY(ARR([用户信息].[用户ID],[用户信息].[用户名称]),[用户信息].[性别]='女' and [用户信息].[年龄]>25 and [用户信息].[注册时间]>'2024-01-01')`

4. 返回一个聚合值

使用[SUM](../aggregate/SUM.md)、[COUNT](../aggregate/COUNT.md)等聚合函数将多行数据聚合为一个值返回。

比如查询满足条件的客户数量：`(QUERY(COUNT([用户信息].[用户ID]),[用户信息].[性别]='女' and [用户信息].[年龄]>25 and [用户信息].[注册时间]>'2024-01-01'))`

5. 多个query函数自动合并查询

页面内多个地方使用query函数时，系统会根据查询模型和条件自动合并，减少对发起的查询请求数量。示例参考：TODO

6. 全量缓存数据在内存中再计算query函数

页面经常做大量query查询时，如果查询的模型数据量不大，可以把数据集设置为[允许下载全量数据]()，系统将数据先全量缓存到内存中，再在内存中进行query函数计算，提升查询性能。示例参考：TODO

7. 与SELECT函数的区别

[SELECT](./SELECT.md) 函数只在SQL端计算，SELECT函数表达式必须放在模型的计算字段或过滤条件中使用，而query函数可以独立构造查询，能放在任何可以使用表达式的地方。

## 场景{#scene}

### 明细填报中取汇总指标数据{#detail-agg}

常用于表单、superpage等明细查询页面中取汇总数据，减少对数据加工的依赖，简化取数逻辑。

比如在门店的产品销售情况填报表单中，表单在初始化时会按照产品维浮动出产品列表，同时需要将要填报的销售数量、销售金额等指标从业务库的销售明细表中汇总计算出来，传统的做法是需要使用数据加工提前汇总好数据再引用，现在可以直接通过`query(sum([销售明细表].[销售数量]))`表达式来取汇总数据。

示例地址：[表单取数](https://demo.succbi.com/v5/DEMO/app/ci.app?:id=fetch-and-calc&:dataPeriod=202212&:orgId=010301&:sheet=query_func)

### 跨表数据校验{#cross-check}

在表单填报场景中，经常需要对填报的数据进行跨表校验以确保数据的准确性和一致性。通过QUERY函数可以灵活地获取其他表中的相关数据，实现复杂的跨表业务规则校验，而不需要创建很多临时的数据加工用来取数。

常见的跨表校验场景：

1. 唯一性校验

比如在新增用户信息时，需要校验用户手机号是否已被使用：
`QUERY(COUNT([用户信息].[手机号]),[用户信息].[手机号]=表单.手机号)>0`

2. 数据一致性校验

在采购订单填报时，需要校验采购金额是否超过预算限额：
`采购金额 > QUERY(SUM([预算表].[剩余金额]),[预算表].[部门ID]=$user.dept_id)`

3. 业务规则校验

在合同审批表单中，校验经办人是否具有对应的业务权限：
`合同金额 <= QUERY([员工权限表].[审批额度],[员工权限表].[员工ID]=$user.id)`

### 复杂统计分析计算{#complex-statistics}

在BI报表分析中，经常需要分析销售趋势和业绩达成情况，比如计算最近12个月的累计销售额来评估业务增长情况。或者在预算管理中需要按月跟踪预算执行进度，计算年度累计预算完成率等。

以计算累计销售额为例:
`QUERY(SUM([销售表].[销售额]),[销售表].[销售日期].[年月] BETWEEN 起始年月 AND 截止年月)`

### 动态数据范围权限控制{#dynamic-ds-auth}

在OA系统中管理公司所有的项目建设情况，包括项目的人力资源、合同、进度等信息。一个员工可以参与多个项目并担任不同的项目角色，这些信息单独记录在`项目成员表`中。

为了实现基于用户项目角色权限进行数据过滤，可以使用QUERY函数动态控制登录用户的数据范围：`[项目信息表].[项目ID] in QUERY(ARR([项目成员表].[项目ID]),[项目成员表].[用户ID]=$user.id)`
