如何在X++中构建带where子句及跨表OR条件的Query查询
X++ 跨多关联表实现跨字段OR模糊匹配方案
你之前两种写法不生效的核心原因:
- 跨数据源单独调用
addQueryFilter/addRange添加的条件,默认会用AND逻辑连接,只有同个数据源下、绑定同个字段的多个Range值才会自动拼成OR条件,跨表场景不会自动生成OR逻辑 - 你写的
addRange版本存在逻辑错误:每调用一次addRange就会生成一个独立的新Range对象,你反复给qbr变量赋值会覆盖之前的Range引用,最后value()只作用在最后一个绑定到TABLE3.c字段的Range上,自然生成的SQL不符合预期。
下面是两种可直接落地的实现方式,生成的SQL和你给出的预期效果完全一致:
方案1:根数据源绑定全表达式Range(兼容性最好,最常用)
核心思路是把所有跨表OR条件拼成一个完整的合法表达式,绑定到最外层根数据源(也就是你的TABLE1)的Range上即可,不需要给子表单独加筛选条件。注意提前配置好子表的关联关系和连接模式。
示例代码:
Query query = new Query(); QueryBuildDataSource tab1, tab2, tab3; QueryBuildRange crossTableOrRange; str searchValue = 'F1'; // 初始化主表数据源 tab1 = query.addDataSource(tableNum(TABLE1), 'tab1'); // 配置左外连接的子表2,指定关联字段 tab2 = tab1.addDataSource(tableNum(TABLE2), 'tab2'); tab2.joinMode(JoinMode::LeftOuter); tab2.addLink(fieldNum(TABLE1, x), fieldNum(TABLE2, x)); // 配置左外连接的子表3,指定关联字段 tab3 = tab1.addDataSource(tableNum(TABLE3), 'tab3'); tab3.joinMode(JoinMode::LeftOuter); tab3.addLink(fieldNum(TABLE1, x), fieldNum(TABLE3, x)); // 绑定跨表OR条件到主表的Range上,这里选RecId做占位绑定字段即可,不影响条件逻辑 crossTableOrRange = tab1.addRange(fieldNum(TABLE1, RecId)); crossTableOrRange.value( strFmt( '(%1.%2 LIKE "*%3*" || %1.%4 LIKE "*%3*" || %5.%6 LIKE "*%3*" || %7.%8 LIKE "*%3*")', tab1.name(), // 主表数据源别名 fieldStr(TABLE1, a), searchValue, fieldStr(TABLE1, aa), tab2.name(), // 子表2数据源别名 fieldStr(TABLE2, b), tab3.name(), // 子表3数据源别名 fieldStr(TABLE3, c) ) );
关键注意点:
- X++ Query语法中模糊匹配的通配符是
*,不是SQL原生的%,Query执行时会自动把*转成对应数据库的通配符,直接写%会被当成普通字符匹配- 逻辑或写
||、逻辑与写&&,不要直接写SQL的OR/AND,避免跨数据库兼容问题- 调用数据源的
name()方法取别名,比硬编码'tab1'这类字符串更稳妥,后续调整数据源别名不需要修改条件表达式
你提到的dirpartytable三表关联的实际业务场景,直接替换对应表名、字段名、关联关系、搜索值即可套用这个模板。
方案2:QueryFilter绑定全局表达式(适合固定全局筛选场景)
如果是给已有Query追加全局筛选条件,或者用AOT Query做动态开发,可以直接把完整的跨表OR表达式作为QueryFilter的值,绑定到主表数据源即可,效果和方案1一致:
QueryFilter crossFilter = query.addQueryFilter(tab1, fieldStr(TABLE1, RecId)); crossFilter.value(strFmt( '(%1.%2 LIKE "*%3*" || %1.%4 LIKE "*%3*" || %5.%6 LIKE "*%3*" || %7.%8 LIKE "*%3*")', tab1.name(), fieldStr(TABLE1, a), searchValue, fieldStr(TABLE1, aa), tab2.name(), fieldStr(TABLE2, b), tab3.name(), fieldStr(TABLE3, c) ));
这个写法生成的筛选条件会固定放在SQL的WHERE最外层,不会随JOIN结构下沉到ON子句,适合不随查询结构变化的固定筛选规则。
避坑提示
- 不要跨数据源单独添加同值的Range/Filter期待自动拼OR,只有同个数据源绑定同个字段的多个Range值才会自动生成OR逻辑
- 不要反复覆盖同一个Range变量后再赋值,每个独立条件对应一个独立的Range/Filter对象,跨表OR逻辑必须写在同一个表达式里
- 不要在Query表达式里直接写原生SQL语法,必须用X++ Query支持的语法规则,否则会被解析器转义导致查询结果错误
内容的提问来源于stack exchange,提问作者devSL
相关产品推荐
相关产品推荐

