多条SQL语句对查询结果集的垂直合并,以及表设计时如何冗余字段

时间:2022-06-07 23:21:47

需求引入

你有一个销售单表A 和一个销售单详情表B 和一个收付款记录表C

A---->B 一对多   A---->C一对多

如果一个销售单有两个详情,三条收款记录

对一个销售单 我们想查询出一个结果集 有销售单的id、详情总额、销售单的收款总额

如果你select A  join B on(B和A的外键) 查询出2条记录结果集

如果你select A  join C on(C和A的外键) 查询出3条记录结果集

那你 如果你select A  join B on(B和A的外键)  join C on(C和A的外键) 查询出2*3=6条记录结果集 然后在sum

如果select语句中有聚合函数(sum count )很可能导致查询的结果不符合需求的要求。因为详情总额只需要对两条记录进行sum  收款进行需要三条 而sum之前我们查出来了六条

解决办法

1. 用两条sql查询 然后通过java对结果集进行合并。

缺点:只能对一些简单的需求,如果多个销售单,还要做分页 而且有 付款记录和详情的搜索条件 JAVA很难做

2. 用两条sql查询  然后就是用sql的垂直合并了

select * from (sql1)  join (sql2) on(sql1.销售单的主键=sql2.销售单的主键) 就是把两条sql当成两个子查询

优点:解决了用java操作List进行合并,做不了分页搜索的问题。因为我们用的一个SQL 无论需求怎么搜索分页,都可以搞定

工作中做某张报表的时候发现的。sql语句含有多个一对多关系的时候 注意影响聚合函数的结果。所以采用了先拆分sql,然后根据需求垂直合并。

设计表结构的时,如何避免出现过长的SQL查询

冗余一些字段,比如你需要对收付款记录的某一个字段(比如金额)做sum 把这个字段冗余到一张额外的表里面。

方法一:每次进行收付款的时候加减这个字段。这样做报表的时候就不必再关联收付款记录表做关联求sum了(这样的话 有哪个接口忘记更新收付款就完蛋了 很难排查)

方法二 :每次进行收付款的时候 从新进行一遍收付款的sum放进销售单里面,比较消耗性能。引入消息队列 异步的操作这种接口。

方法三  :收付款的时候多开一个线程,去更新sum字段

当我们把计算逻辑(比如钱的增量)写在SQL里面的时候 可以不用乐观锁,因为SQL会读到其他已经提交的事物,但是如果这个钱是先计算好,然后直接update的 需要用乐观锁