MySQL行转列和多表连接数据合计计算

今天在写一个SQL时发了很长的时间,要求是关连8张表将这些表中属于同一项目的费用汇总计算出来在一列中。
效果图:
在这里插入图片描述

 # 合同收款
select F_xmmc,F_skje from w_htsk
# 项目信息表
select * from w_t_bproject_item
#材料付款
select * from w_clfkuan
#劳务付款
select * from w_lwfksqing
#租赁付款
select * from w_paymentappbill
#分包付款
select * from w_fenbaofksq
#报销费用表也就是所有的报销费用数据
#费用报销明细
select * from w_fybxentry
#费用报销
select * from w_fybxBill

原先我的SQL是这样的:
首先项目间接费是从费用报销和费用报销明细来的
先看看这两个表的结构吧
费用报销表:
在这里插入图片描述
说明:里面保存了项目名称和报销记录,测试数据每个项目有两条记录
费用报销明细表:
在这里插入图片描述
说明:里面保存了每一项报销的金额,根据项目名称来关联报销表。
计算每个项目的间接费用

SELECT F_ssxm,w_fybxBill.ID,
    MAX(CASE F_fykm WHEN '业务招待费' THEN F_je ELSE 0 END ) 业务招待费,
    MAX(CASE F_fykm WHEN '其它' THEN F_je ELSE 0 END ) 其它,
		MAX(CASE F_fykm WHEN '职员餐费' THEN F_je ELSE 0 END ) 职员餐费,
		MAX(CASE F_fykm WHEN '通讯费' THEN F_je ELSE 0 END ) 通讯费,
		MAX(CASE F_fykm WHEN '人员工资' THEN F_je ELSE 0 END ) 人员工资,
		MAX(CASE F_fykm WHEN '工程保险费' THEN F_je ELSE 0 END ) 工程保险费,
		MAX(CASE F_fykm WHEN '消费设施费' THEN F_je ELSE 0 END ) 消费设施费,
		MAX(CASE F_fykm WHEN '福利费' THEN F_je ELSE 0 END ) 福利费,
		MAX(CASE F_fykm WHEN '税费' THEN F_je ELSE 0 END ) 税费
FROM w_fybxBill,w_fybxentry where w_fybxBill.ID=w_fybxentry.REFID
GROUP BY w_fybxBill.ID

在这里插入图片描述
行转列将每个项目的每项费用得到

select F_ssxm '项目名称',SUM(a.业务招待费+a.其它+a.F_ssxm+a.职员餐费+a.通讯费+a.人员工资+a.工程保险费+a.消费设施费+a.福利费+a.税费) 合计 from (SELECT F_ssxm,w_fybxBill.ID,
    MAX(CASE F_fykm WHEN '业务招待费' THEN F_je ELSE 0 END ) 业务招待费,
    MAX(CASE F_fykm WHEN '其它' THEN F_je ELSE 0 END ) 其它,
		MAX(CASE F_fykm WHEN '职员餐费' THEN F_je ELSE 0 END ) 职员餐费,
		MAX(CASE F_fykm WHEN '通讯费' THEN F_je ELSE 0 END ) 通讯费,
		MAX(CASE F_fykm WHEN '人员工资' THEN F_je ELSE 0 END ) 人员工资,
		MAX(CASE F_fykm WHEN '工程保险费' THEN F_je ELSE 0 END ) 工程保险费,
		MAX(CASE F_fykm WHEN '消费设施费' THEN F_je ELSE 0 END ) 消费设施费,
		MAX(CASE F_fykm WHEN '福利费' THEN F_je ELSE 0 END ) 福利费,
		MAX(CASE F_fykm WHEN '税费' THEN F_je ELSE 0 END ) 税费
FROM w_fybxBill,w_fybxentry where w_fybxBill.ID=w_fybxentry.REFID
GROUP BY w_fybxBill.ID) a GROUP BY a.F_ssxm

在这里插入图片描述
现在将每个项目的间接费用拿到
那么我们现在来看下其它6个表的数据
在这里插入图片描述
保存的项目信息,这里只用倒项目名称
在这里插入图片描述
得到数据收入金额
在这里插入图片描述
得到材料付款金额
在这里插入图片描述
得到劳务付款金额
在这里插入图片描述
得到租赁付款金额
在这里插入图片描述
得到分包付款金额
重点就是这6个表的数据了,可以发现,有的金额一条数据有的两条数据,也就是说业务上没有限制录入数据的次数,因为不可能说买材料刚刚好一次买完整了,或者其它的记录也不可能一次就录入完整了。
之前的SQL我是这样写的:

select t.F_Name '项目名称',ifnull(SUM(h.F_skje),0) '收入',ifnull(SUM(c.F_fkje),0) '材料',ifnull(SUM(l.F_yfkje),0) '劳务',ifnull(SUM(p.F_FKmoney),0) '租赁',ifnull(SUM(f.F_htje),0) '分包',ifnull(SUM(hj.合计),0) '间接费',ifnull(SUM(h.F_skje),0)-ifnull(SUM(c.F_fkje),0)-ifnull(SUM(l.F_yfkje),0)-ifnull(SUM(p.F_FKmoney),0)-ifnull(SUM(f.F_htje),0)-ifnull(SUM(hj.合计),0) '项目毛利',ifnull((ifnull(SUM(h.F_skje),0)-ifnull(SUM(c.F_fkje),0)-ifnull(SUM(l.F_yfkje),0)-ifnull(SUM(p.F_FKmoney),0)-ifnull(SUM(f.F_htje),0)-ifnull(SUM(hj.合计),0))/ifnull(SUM(h.F_skje),0),0) '毛利率' from w_t_bproject_item t
LEFT OUTER JOIN w_htsk h ON(t.F_Name=h.F_xmmc)
LEFT OUTER JOIN w_clfkuan c ON(t.F_Name=c.F_ssxm)
LEFT OUTER JOIN w_lwfksqing l ON(t.F_Name=l.F_ssxm)
LEFT OUTER JOIN w_paymentappbill p ON(t.F_Name=p.F_FKssxm)
LEFT OUTER JOIN w_fenbaofksq f ON(t.F_Name=f.F_ssxm)
LEFT OUTER JOIN (select F_ssxm '项目名称',SUM(a.业务招待费+a.其它+a.F_ssxm+a.职员餐费+a.通讯费+a.人员工资+a.工程保险费+a.消费设施费+a.福利费+a.税费) 合计 from (SELECT F_ssxm,w_fybxBill.ID,
    MAX(CASE F_fykm WHEN '业务招待费' THEN F_je ELSE 0 END ) 业务招待费,
    MAX(CASE F_fykm WHEN '其它' THEN F_je ELSE 0 END ) 其它,
		MAX(CASE F_fykm WHEN '职员餐费' THEN F_je ELSE 0 END ) 职员餐费,
		MAX(CASE F_fykm WHEN '通讯费' THEN F_je ELSE 0 END ) 通讯费,
		MAX(CASE F_fykm WHEN '人员工资' THEN F_je ELSE 0 END ) 人员工资,
		MAX(CASE F_fykm WHEN '工程保险费' THEN F_je ELSE 0 END ) 工程保险费,
		MAX(CASE F_fykm WHEN '消费设施费' THEN F_je ELSE 0 END ) 消费设施费,
		MAX(CASE F_fykm WHEN '福利费' THEN F_je ELSE 0 END ) 福利费,
		MAX(CASE F_fykm WHEN '税费' THEN F_je ELSE 0 END ) 税费
FROM w_fybxBill,w_fybxentry where w_fybxBill.ID=w_fybxentry.REFID
GROUP BY w_fybxBill.ID) a GROUP BY a.F_ssxm) hj ON(t.F_Name=hj.项目名称)
GROUP BY t.ID;

在这里插入图片描述
我们现在对数据就能发现:收入没错100000+8000=108000,那我们看租赁天斗公路明明只有5000,而现在的结果是10000,现在就看出加了两次,每条数据都当两条数据加了两次。也就是说在每项费用加之前都拿了两次。
优化后的SQL:

select t.F_Name '项目名称',ifnull(h.F_skje,0) '收入',ifnull(c.F_fkje,0) '材料',ifnull(l.F_yfkje,0) '劳务',ifnull(p.F_FKmoney,0) '租赁',ifnull(f.F_htje,0) '分包',ifnull(hj.合计,0) '间接费',ifnull(h.F_skje,0)-ifnull(c.F_fkje,0)-ifnull(l.F_yfkje,0)-ifnull(p.F_FKmoney,0)-ifnull(f.F_htje,0)-ifnull(hj.合计,0) '项目毛利',ifnull((ifnull(h.F_skje,0)-ifnull(c.F_fkje,0)-ifnull(l.F_yfkje,0)-ifnull(p.F_FKmoney,0)-ifnull(f.F_htje,0)-ifnull(hj.合计,0))/ifnull(h.F_skje,0),0) '毛利率' from w_t_bproject_item t
LEFT OUTER JOIN (select F_xmmc,SUM(F_skje) F_skje from w_htsk GROUP BY F_xmmc) h ON(t.F_Name=h.F_xmmc)
LEFT OUTER JOIN (select F_ssxm,SUM(F_fkje) F_fkje from w_clfkuan GROUP BY F_ssxm) c ON(t.F_Name=c.F_ssxm)
LEFT OUTER JOIN (select F_ssxm,SUM(F_yfkje) F_yfkje from w_lwfksqing GROUP BY F_ssxm) l ON(t.F_Name=l.F_ssxm)
LEFT OUTER JOIN (select F_FKssxm,SUM(F_FKmoney) F_FKmoney from w_paymentappbill GROUP BY F_FKssxm) p ON(t.F_Name=p.F_FKssxm)
LEFT OUTER JOIN (select F_ssxm,SUM(F_htje) F_htje from w_fenbaofksq GROUP BY F_ssxm) f ON(t.F_Name=f.F_ssxm)
LEFT OUTER JOIN (select F_ssxm '项目名称',SUM(a.业务招待费+a.其它+a.F_ssxm+a.职员餐费+a.通讯费+a.人员工资+a.工程保险费+a.消费设施费+a.福利费+a.税费) 合计 from (SELECT F_ssxm,w_fybxBill.ID,
    MAX(CASE F_fykm WHEN '业务招待费' THEN F_je ELSE 0 END ) 业务招待费,
    MAX(CASE F_fykm WHEN '其它' THEN F_je ELSE 0 END ) 其它,
		MAX(CASE F_fykm WHEN '职员餐费' THEN F_je ELSE 0 END ) 职员餐费,
		MAX(CASE F_fykm WHEN '通讯费' THEN F_je ELSE 0 END ) 通讯费,
		MAX(CASE F_fykm WHEN '人员工资' THEN F_je ELSE 0 END ) 人员工资,
		MAX(CASE F_fykm WHEN '工程保险费' THEN F_je ELSE 0 END ) 工程保险费,
		MAX(CASE F_fykm WHEN '消费设施费' THEN F_je ELSE 0 END ) 消费设施费,
		MAX(CASE F_fykm WHEN '福利费' THEN F_je ELSE 0 END ) 福利费,
		MAX(CASE F_fykm WHEN '税费' THEN F_je ELSE 0 END ) 税费
FROM w_fybxBill,w_fybxentry where w_fybxBill.ID=w_fybxentry.REFID
GROUP BY w_fybxBill.ID) a GROUP BY a.F_ssxm) hj ON(t.F_Name=hj.项目名称)
GROUP BY t.ID;

在这里插入图片描述
这时候数据就对了,这是因为在数据计算之前就已经将每项费用的合计都已经计算好了。
在这里优化花了不少时间,就记录下来了。如果有大佬看见有更好的方式希望不吝赐教。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值