blinkfox / fenix

This is an extension library to the Spring Data JPA complex or dynamic SQL query. 这是一个比 MyBatis 更加强大的 Spring Data JPA 扩展库,为解决复杂动态 JPQL (或 SQL) 而生。https://blinkfox.github.io/fenix
https://blinkfox.github.io/fenix
Apache License 2.0
348 stars 73 forks source link

where 标签问题 #43

Closed onlylxz closed 3 years ago

onlylxz commented 3 years ago

模板语句 SELECT * FROM (SELECT t1.name as name FROM table1 t1 <where> <andStartsWith /> 不满足 <andIn /> 不满足 </where> ) a

会生成这样的sql语句 select * from (SELECT t1.name as name FROM table1 t1 where ) a

多出一个where关键字,请问子查询这样不能支持吗?

pengten commented 3 years ago

只要有标签,就会加where。 可以在where中加上类似 1=1

pengten commented 3 years ago

@blinkfox 老师确认下这个呢?感觉是个BUG, 是否应该在WhereHandler结束时设置prependWhere=false image

blinkfox commented 3 years ago

最近没时间,你们可以调试看看,或者换一种写法,<where /> 标签,是至上而下解析的。

onlylxz commented 3 years ago

@onlylxz 目前可以用重写快速解决该问题。 你可以重写一个 WhereHandler , 然后在启动后调用 FenixConfig.add("where", MyWhereHandler::new); 覆盖掉原有 where 处理。 image

QQQ

pengten commented 3 years ago

@onlylxz 目前看起来还是只能添加 1=1 来解决您遇到的问题。 <where />标签后面只要有内容,则必定会添加 WHERE 关键字。目前设计如此。

pengten commented 3 years ago

@onlylxz 目前可以用重写快速解决该问题。 你可以重写一个 WhereHandler , 然后在启动后调用 FenixConfig.add("where", MyWhereHandler::new); 覆盖掉原有 where 处理。 image

QQQ

该方法不可行,会影响到其他的另一些能力。:(

onlylxz commented 3 years ago

@pengten 好的,还是感谢您帮我解答,目前还有一个分页 count 的问题,我测试整理完成后发出来。都是原生sql导致的。

onlylxz commented 3 years ago

使用这种子查询的时候(去掉子查询后没问题) SELECT (SELECT t2.age FROM table2 t2 WHERE t1.id = t2.id) AS age, t1.name AS name FROM table1 t1;

会生成错误的sql语句 count 语句: SELECT count(*) AS count FROM table2 t2 WHERE t1.id = t2.id) AS age, t1.name AS name FROM table1;

如果使用这样的在外面包一层就是能生成正常的sql count: SELECT * FROM (SELECT (SELECT t2.age FROM table2 t2 WHERE t1.id = t2.id) AS age, t1.name AS name FROM table1 t1) a;

包一层后生成的count语句可以正常使用 SELECT count(*) AS count FROM (SELECT (SELECT t2.age FROM table2 t2 WHERE t1.id = t2.id) AS age, t1.name AS name FROM table1 t1) a;

blinkfox commented 3 years ago

我抽下班时间看了下。

  1. 关于 <where /> 标签的问题需要改造下 WhereHandler 类的代码,加一个判断,如果之后没有生成任何 SQL,就把 prependWhere 设置为 false 即可,而且 SQL 写法就得用这种 <where></where> 包裹的写法了,以前这种 <where /> 平级的写法就不行了,不过我看你就是用的包裹写法的,这个没啥问题。

我晚上有空改一下,发一版,代码大概修改点如下:

public class WhereHandler implements FenixHandler {

    /**
     * 根据 {@link BuildSource} 的相关参数来动态构建出 {@code WHERE} 语句后的 SQL 或 JPQL 语句及参数信息.
     *
     * @param source 构建所需的 {@code BuildSource} 资源对象
     */
    @Override
    public void buildSqlInfo(BuildSource source) {
        // 进入此方法后,将 prependWhere 设置为 true,
        // 说明后续的动态条件的 SQL 语句中都要判断是否要前置添加 WHERE 关键字,并去除掉 WHERE 后面的 AND 或者 OR 关键字.
        // 在各个动态标签或文本标签中,如果处理了 WHERE 标签的情况之后,就再将 prependWhere 设置为 false 即可.
        SqlInfo sqlInfo = source.getSqlInfo();
        String oldSql = sqlInfo.getJoin().toString();
        sqlInfo.setPrependWhere(true);
        FenixXmlBuilder.buildSqlInfo(source.getNamespace(), sqlInfo, source.getNode(), source.getContext());
        if (oldSql.equals(sqlInfo.getJoin().toString())) {
            sqlInfo.setPrependWhere(false);
        }
    }

}
  1. 关于 Fenix 中的求总数 count 语句,是会将第一个 SELECT 与 FROM 之间的数据统一替换为 COUNT(*) 的,所以,你的字段级子查询就会有问题,目前来看你包裹一层才行,不过这种子查询是不好的 SQL 写法,你应该用表连接来替代这种子查询,效率才高。你的写法应该换一下,尽量不要用子查询的。
onlylxz commented 3 years ago

@blinkfox 关于count确实是因为实际的sql 语句比我写的要复杂很多😂,而且由于很多老的业务不得不使用非常复杂的子查询来兼容。不过只是包过一层这个倒是影响不大。

blinkfox commented 3 years ago

@blinkfox

  1. 对于复杂 SQL,为了效率你可以自己写 SQL 语句的,写到 @QueryFenix 注解的 countQuery 属性中即可,并去掉相关的字段子查询、分组排序等。
  2. 关于 <where /> 标签我想了下,为了向前兼容,以前的标签暂时不改,创建新的标签来用新的逻辑实现。
onlylxz commented 3 years ago

好的,谢谢

blinkfox commented 3 years ago

@onlylxz 新版本已经发布了,你直接使用 v2.5.0 版本,新增了 trimWhere 标签,后续你都用这个标签包裹动态条件就行。