Skip to content

"join"语法和"key@"引用赋值语法冲突 #341

Open

Description

@Shuai-S

环境信息

  • 系统: macos 11.5.2 (20G95)
  • JDK: 1.8.0_261
  • 数据库: MySQL 5.7.14
  • APIJSON: 4.7.2

问题描述
"join"语法和"key@"引用赋值语法冲突
join后会引用赋值语法也会根据返回数据的总条数继续做关联查询,返回的数据也不是以含join的sql解析出来的数据,而是引用复制生成sql返回的数据
image

当join语法中含有sum函数时 不会返回sum结果,会返回引用赋值关联查询的数据
image

错误信息
以下为生成的4条sql

<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
已生成 1 条 SQL
execute startTime = 1637317650951
database = ; schema = ; sql =
SELECT count(*) AS count FROM pre_sales_project_info AS PreSalesProjectInfo
LEFT JOIN ( SELECT project FROM code_info WHERE ( (del_flag = 0) AND (bound_type = 0) ) ) AS CodeInfo ON CodeInfo.project = PreSalesProjectInfo.id WHERE ( (PreSalesProjectInfo.deleted = 0) )

<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
已生成 2 条 SQL
execute startTime = 1637317651302
database = ; schema = ; sql =
SELECT PreSalesProjectInfo.*, CodeInfo.project,CodeInfo.budget FROM pre_sales_project_info AS PreSalesProjectInfo
LEFT JOIN ( SELECT project,budget FROM code_info WHERE ( (del_flag = 0) AND (bound_type = 0) ) ) AS CodeInfo ON CodeInfo.project = PreSalesProjectInfo.id WHERE ( (PreSalesProjectInfo.deleted = 0) ) ORDER BY PreSalesProjectInfo.gmtCreate DESC LIMIT 2

<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
已生成 3 条 SQL
execute startTime = 1637317651343
database = ; schema = ; sql =
SELECT project,budget FROM code_info WHERE ( (del_flag = 0) AND (bound_type = 0) AND (project = 1637054928436) ) LIMIT 1

<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
已生成 4 条 SQL
execute startTime = 1637317651356
database = ; schema = ; sql =
SELECT project,budget FROM code_info WHERE ( (del_flag = 0) AND (bound_type = 0) AND (project = 1637051014468) ) LIMIT 1

Activity

  1. TommyLemon commented on Nov 20, 2021

    @TommyLemon
    Member

    第一个问题换最新版 4.8.0 再试试。
    https://github.com/APIJSON/APIJSON-Demo/releases/tag/4.8.0

    第二个没问题,只是 Postman 把 PresalesProjectInfo 和 CodeInfo 顺序倒过来了,用 APIAuto 就仍然保持顺序
    http://apijson.cn/api/

  2. Shuai-S commented on Nov 22, 2021

    @Shuai-S
    Author

    第一个问题换最新版 4.8.0 再试试。 https://github.com/APIJSON/APIJSON-Demo/releases/tag/4.8.0

    第二个没问题,只是 Postman 把 PresalesProjectInfo 和 CodeInfo 顺序倒过来了,用 APIAuto 就仍然保持顺序 http://apijson.cn/api/

    你好,第一个问题4.8.0没有解决问题,还是会生成关联查询sql 一共会生成和执行一个count(*)的sql 一个left join的sql 和n条查询数据的关联查询sql

    第二个问题可能是我描述的不清晰的问题,主要问题是返回的sum(budget) 不是根据left join查出来的budget,而是查询出来的progect=1的单条数据的budget

  3. TommyLemon commented on Nov 22, 2021

    @TommyLemon
    Member

    第一个问题我这边复现了 bug,当 JOIN 副表有 JOIN ON 外的条件时会导致用不上查询缓存:
    image
    image

    去掉 "userId": 93793 这个条件后正常。
    image
    image

    应该是这里处理有问题,导致没有把引用赋值键值对放在最前
    https://github.com/Tencent/APIJSON/blob/master/APIJSONORM/src/main/java/apijson/orm/AbstractParser.java
    image

    目前的解决方法是把

    				tableObj = newTableObj;
    				request.put(tableKey, tableObj);

    改成

    				tableObj.clear();
    				tableObj.putAll(newTableObj);

    感谢反馈

  4. Shuai-S commented on Nov 22, 2021

    @Shuai-S
    Author

    导致用不上查询缓存:

    你好,tableObj.clear();
    tableObj.putAll(newTableObj);这个无效的:因为tableObj是无序的,替换成tableObj = newTableObj;后可以把引用赋值键值对放在最前,但是返回的关联数据一直是第一条,数据是重复的

    image

    第二个问题,去除副表查询条件后不返回sum(budget)字段
    image

    麻烦你们了,谢谢

  5. TommyLemon commented on Nov 22, 2021

    @TommyLemon
    Member

    com.alibaba.fastjson.JSONObject 构造方法可以传参 ordered = true 指定内部使用 LinkedHashMap 保证键值对顺序

  6. TommyLemon commented on Nov 22, 2021

    @TommyLemon
    Member

    第二个问题我这边也复现了,JOIN 中副表有 SQL 函数时不返回 SQL 函数对应的值
    image

    应该是 AbstractSQLExecutor.onPutColumon 内部逻辑问题(大概率)或者 JDBC 未返回(小概率)
    https://github.com/Tencent/APIJSON/blob/master/APIJSONORM/src/main/java/apijson/orm/AbstractSQLExecutor.java
    image

  7. Shuai-S commented on Nov 23, 2021

    @Shuai-S
    Author

    您好,大佬,我想了解一下这两个问题的大概修复时间节点
    或者有什么临时解决办法吗?谢谢🙏

  8. TommyLemon commented on Nov 23, 2021

    @TommyLemon
    Member

    您好,大佬,我想了解一下这两个问题的大概修复时间节点 或者有什么临时解决办法吗?谢谢🙏

    预计下周末,顺便会让 JOIN ON 新增支持多个条件。

    第二个问题,应该只要把

    SELECT Table2.column1, Table2.column2..  FROM Table1 LEFT JOIN (SELECT column1, column2 FROM Table2 ..) AS Table2

    改成

    SELECT Table2.*  FROM Table1 LEFT JOIN (SELECT column1, column2 FROM Table2 ..) AS Table2

    就可以解决,源码在 AbstractSQLConfig.getColumnString

  9. TommyLemon commented on Dec 4, 2021

    @TommyLemon
    Member

    com.alibaba.fastjson.JSONObject 构造方法可以传参 ordered = true 指定内部使用 LinkedHashMap 保证键值对顺序

    ResultSetMetaData.getTableName 副表的返回值为 "",导致 APIJSON 在 LEFT/RIGHT JOIN 的副表中不返回 SQL 函数执行值

    8EB69FC4FF8EFFEA4B21B68E25EE1EC6

    https://bugs.mysql.com/bug.php?id=94585

    第一个问题也是这个问题导致,副表所有字段对应 ResultSetMetaData.getTableName 是 "",导致没用上缓存,然后重新查询,所以执行的 SQL 次数增加。

    Demo 中 mysql-connector-java 8.0.22 复现,改为最新版 8.0.27 仍然复现。
    https://mvnrepository.com/artifact/mysql/mysql-connector-java

    改用 8.0.0 前一个版本 6.0.6 问题更大
    image

    PostgreSQL 一样会对 SQL 函数返回 ResultSetMetaData.getTableName 是 "",看来得调整下副表字段存放策略。

  10. TommyLemon commented on Dec 7, 2021

    @TommyLemon
    Member
  11. Shuai-S commented on Dec 9, 2021

    @Shuai-S
    Author

    好的,谢谢解决问题,我试试

  12. Shuai-S commented on Dec 16, 2021

    @Shuai-S
    Author

    第一个问题我这边复现了 bug,当 JOIN 副表有 JOIN ON 外的条件时会导致用不上查询缓存

    大佬,您好,其他问题都已经解决,还这个问题没有解决,当 JOIN 副表有 JOIN ON 外的条件时会导致用不上查询缓存

    image

    希望能再看一下,谢谢

  13. TommyLemon commented on Dec 16, 2021

    @TommyLemon
    Member

    导致用不上查询缓存:

    你好,tableObj.clear(); tableObj.putAll(newTableObj);这个无效的:因为tableObj是无序的,替换成tableObj = newTableObj;后可以把引用赋值键值对放在最前,但是返回的关联数据一直是第一条,数据是重复的

    image

    第二个问题,去除副表查询条件后不返回sum(budget)字段 image

    麻烦你们了,谢谢

    还是这样改下看看,截屏里主表出现重复数据是因为主表与副表是一对多关系,用 LEFT JOIN 查到的结果集本身就会重复,可以用 GROUP BY 主表 id 或 DISTINCT 主表 id 来去重。

    上次调试时发现有时副表数据为空没有缓存空对象 {} 到 AbstractSQLExecutor 的 cacheMap,导致重新查副表,然后又查到空的对象,有了多余的的 SQL 执行

  14. TommyLemon commented on Dec 24, 2021

    @TommyLemon
    Member

    @Shuai-S 解决了吗?

  15. Shuai-S commented on Dec 28, 2021

    @Shuai-S
    Author

    您好,最近这段时间比较忙,刚刚试了一下,
    具体问题是当JOIN 副表有 JOIN ON 外的条件时,不会走缓存
    1111

    是因为副表中没有对应的数据,缓存为空导致执行了多余的sql查询副表吗?

  16. TommyLemon commented on Dec 28, 2021

    @TommyLemon
    Member

    是因为副表中没有对应的数据,缓存为空导致执行了多余的sql查询副表吗?

    看起来不像这个原因(虽然我之前看到这个原因导致额外的 SQL 查询),因为图中 SQL 缓存了 1 条,但返回的有数据的副表记录缺不止一条,图中就有 3 条了。

  17. TommyLemon commented on Dec 28, 2021

    @TommyLemon
    Member

    导致用不上查询缓存:

    你好,tableObj.clear(); tableObj.putAll(newTableObj);这个无效的:因为tableObj是无序的,替换成tableObj = newTableObj;后可以把引用赋值键值对放在最前,但是返回的关联数据一直是第一条,数据是重复的

    image

    第二个问题,去除副表查询条件后不返回sum(budget)字段 image

    麻烦你们了,谢谢

    				tableObj = newTableObj;
    				request.put(tableKey, tableObj);

    改成

    				tableObj.clear();
    				tableObj.putAll(newTableObj);

    之前你这样改过后,缓存的 SQL 就变多了,执行的 SQL 变少了。可以再看看

    WHERE ( (del_flag = 0) AND (bound_type = 0) AND (project = 1637054928436) ) 

    中 project = 1637054928436 是不是提到最前了

    WHERE (  (project = 1637054928436) AND (del_flag = 0) AND (bound_type = 0) ) 

    是这样的话就对了。

    当然不改的话数据一对一、多对一应该没问题,只是额外多了一些不必要的性能开销;一对多、多对多且不用 GROUP BY/DISTINCT 去重的话就可能导致副表数据重复

  18. TommyLemon commented on Jan 2, 2022

    @TommyLemon
    Member

    @Shuai-S 已解决
    a8bad69

    可以用 4.8.3 的 jar 包
    https://github.com/APIJSON/APIJSON-Demo/tree/master/APIJSON-Java-Server/APIJSONBoot-MultiDataSource/libs

    image
    image
    image

    {
        "[]": {
            "query": 2,
            "page": 0,
            "count": 20,
            "join": "</Moment/id@",
            "Comment": {
                "@order": "date-"
            },
            "Moment": {
                "@column": "id,userId,content",
                "id@": "/Comment/userId",
                "userId": 93793
            }
        },
        "info@": "/[]/info",
        "@explain": true
    }
  19. Shuai-S commented on Jan 6, 2022

    @Shuai-S
    Author

    谢谢大佬,我升级版本试一下

  20. TommyLemon commented on Mar 6, 2022

    @TommyLemon
    Member

    您好,大佬,我想了解一下这两个问题的大概修复时间节点 或者有什么临时解决办法吗?谢谢🙏

    预计下周末,顺便会让 JOIN ON 新增支持多个条件。

    第二个问题,应该只要把

    SELECT Table2.column1, Table2.column2..  FROM Table1 LEFT JOIN (SELECT column1, column2 FROM Table2 ..) AS Table2

    改成

    SELECT Table2.*  FROM Table1 LEFT JOIN (SELECT column1, column2 FROM Table2 ..) AS Table2

    就可以解决,源码在 AbstractSQLConfig.getColumnString

    顺便

    已支持 JOIN 带多个 ON 条件
    f7b82fd

    {
        "[]": {
            "join": "</User",
            "Comment": {},
            "User": {
                "sex@": "/Comment/toId",
                "id@": "/Comment/userId"
            }
        },
        "@explain": true
    }

    FBA0502D-FFEC-4A68-90A3-9BDC43EC16EE

    {
        "[]": {
            "count": 3,
            "join": {
                "&/User": {
                    "name$": "%a%",
                    "tag*~": "a",
                    "@combine": "name$,tag*~",
                    "@column": null,
                    "@group": "id",
                    "@having": "(id)%7!=0",
                    "@order": "id+"
                }
            },
            "Comment": {
                "@column": "userId"
            },
            "User": {
                "id@": "/Comment/userId",
                "@column": "id;count(1)",
                "@group": "id",
                "@having": "(id)%5>1",
                "@order": "id-"
            }
        },
        "@explain": true
    }

    image

  21. TommyLemon commented on Feb 1, 2025

    @TommyLemon
    Member

    #198 (comment)

    @Shuai-S
    已解决 SQL JOIN 在一对多或多对多时返回单独查询的重复副表数据,而不是 SQL 结果集里的副表数据。
    (之前必须用 DISTINCT / ORDER BY 去重 或 调换主副表顺序(有的还需要把 LEFT JOIN 改为 RIGHT JOIN) 来解决,但可能结果不符合某些需求)
    2f5d947

    Image

    https://apijson.cn/api/?send=true&type=JSON&url=http%3A%2F%2Flocalhost%3A8080%2Fget&json={%22[]%22:{%22count%22:3,%22join%22:%22%3C%2FComment%22,%22User%22:{%22@column%22:%22id%2Cname%22},%22Comment%22:{%22@column%22:%22id%2CuserId%22,%22userId@%22:%22%2FUser%2Fid%22}},%22@explain%22:true}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions