mysql分组之后选取分组字段以外的字段以及选择组中特定的一行,附sql语句以及ActiveRecord查询语句

2 篇文章 0 订阅

源自oa需求,系统中有两张表: 申请表 applies和 审批表audits,applies和audits是一对多的关系,也就是说一张申请单下面会对应多张审批单,但是有个时候会出现这种情况,同一个人在同一个申请单下会有多条审批单记录,即:这条申请单下有多级审批节点都是同一个人,如此一来,在该审批人的审批事务列表中就会出现多条对应于同一个申请单的审批单了,从数据表结构来分析的话,这其实是正常应该出现的情况,因为这个人的确是审批了多次,但是与现在需求要求不一致。

audits
idapply_idcreated_at其他字段
112019-03-27 12:50:00
222019-03-27 12:50:01
322019-03-27 12:50:02
432019-03-27 12:50:03
思路
  • 利用group by语句,按照 apply_id进行分组,但是这样有个限制,在sql中,select 后面跟随的字段必须是跟group by中进行分组的字段相关联的字段,只能选择与group by 相同的字段,若要选择其他未group by 的字段,则必须通过聚合函数合成为一个字段才能展示出来,比如:
select a from A group by a

或者

select a,sum(b) from A group by a
但是

当需要选择group by以外的字段的时候,就出现问题了,以上面的样表为例,我们不仅仅需要选择出apply_id,我们还需要选择出created_at以及其他的字段,也就是说,在group by分组完之后,还需要从组里面将其他的字段各选出一个值出来,比如,上面的表中如果group by 之后,数据应该先是这个样子的:

idapply_idcreated_at其他字段
222019-03-27 12:50:01
322019-03-27 12:50:02

apply_id是一样的,但是created_at id 以及其他字段的值,是不一样的!但是我们最终的需要记录只要一条就够了!也就是还得继续从这个分出来的小组里面继续选出一条来。

最终解决方案

使用mysql的groupconcat函数配合substring_index函数

select distinct (a.apply_id), substring_index(group_concat(a.created_at order by a.id desc), ',', 1) ct 
from eams_edu3_test.audits a 
inner join eams_edu3_test.applies ap 
on ap.id = a.apply_id AND ap.school_id = 16 
WHERE a.`school_id` = 16 
group by a.apply_id LIMIT 11

groupconcat的作用即是将组中的该字段的值全部用,
拼接起来,这里还有一个小技巧,在groupconcat中还可以使用order by进一步进行排序再进行连接,然后使用substring_index截取第一个元素,这样即得到了我们所需要的元素。

另外:我的项目是使用的ruby语言,最终的ruby代码如下:

      @search = Audit.joins(:apply).where("applies.business_id != ? and applies.status != ?", Business::REVERT, Apply::STATE_REVERTED).where(auditor_id: current_user.id, available: true).ransack params[:q]
      @audits = @search.result.includes(apply: [:repair_sheet, :leave_sheet, :purchase_apply_sheet, :contract_sheet, :business]).includes(:applicant).
          select(:apply_id, "substring_index(group_concat(audits.id order by audits.created_at desc), ',', 1) id",
                 "substring_index(group_concat(audits.created_at order by audits.created_at desc), ',', 1) created_at",
                 "substring_index(group_concat(audits.status order by audits.created_at desc), ',', 1) status" ,
                 "substring_index(group_concat(audits.remark order by audits.created_at desc), ',', 1) remark",
                 "substring_index(group_concat(audits.stage order by audits.created_at desc), ',', 1) stage").
          group("audits.apply_id").
          order("field(substring_index(group_concat(audits.status order by audits.created_at desc), ',', 1), '#{Audit::UNREAD}') desc, created_at desc").
          page(params[:page] || 1).per(per_page)

参考网址:https://www.periscopedata.com/blog/selecting-only-one-row-per-group

  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值