SQL 层面行转列

背景:

如果对一些评论、点赞、收藏等互动数据,使用了按照 type 分类存储,num 也是对应的。

这样如果创建一个帖子,那么就会出现 3 行数据(type 不同,num 不同,对应评论点赞和收藏),那如果我返回给前端,只想返回一行。

即 3 行数据转化为 3 列属性(评论、点赞、收藏)。

本文就是一个项目中的一个举例,不再单独举例子。

这里只关注了 sql编写,到 mapper 中怎么写,关于中间接口的定义,就不再赘述。

前端需要的字段都在,AlbumListVo中,不代表所有的都在一个数据表中,所以需要联查才可以。

java 复制代码
@Data
@Schema(description = "专辑信息")
public class AlbumInfoVo {

    @NotEmpty(message = "专辑标题不能为空")
    @Length(min = 2, message = "专辑标题的长度必须大于2")
    @Schema(description = "标题", required=true)
    private String albumTitle;

    @Positive(message = "三级分类不能为空")
    @Schema(description = "三级分类id", required=true)
    private Long category3Id;

    @NotEmpty(message = "专辑简介不能为空")
    @Schema(description = "专辑简介", required=true)
    private String albumIntro;

    @NotEmpty(message = "专辑封面不能为空")
    @Schema(description = "专辑封面图", required=true)
    private String coverUrl;

    @Schema(description = "预计更新多少集")
    private Integer estimatedTrackCount;

    @Schema(description = "专辑简介,富文本")
    private String albumRichIntro;

    @NotEmpty(message = "付费类型不能为空")
    @Schema(description = "付费类型: 0101-免费、0102-vip免费、0103-付费", required=true)
    private String payType;

    @Schema(description = "价格类型: 0201-单集 0202-整专辑")
    private String priceType;

    @Schema(description = "原价")
    @JsonSerialize(using = Decimal2Serializer.class)
    private BigDecimal price;

    @Schema(description = "0.1-9.9  不打折 -1")
    @JsonSerialize(using = Decimal2Serializer.class)
    private BigDecimal discount = new BigDecimal(-1);

    @Schema(description = "0.1-9.9 不打折 -1")
    @JsonSerialize(using = Decimal2Serializer.class)
    private BigDecimal vipDiscount = new BigDecimal(-1);

    @Schema(description = "免费试听集数")
    private Integer tracksForFree;

    @Schema(description = "每集免费试听秒数")
    private Integer secondsForFree;

    @Schema(description = "购买须知,富文本")
    private String buyNotes;

    @Schema(description = "专辑卖点,富文本")
    private String sellingPoint;

    @Schema(description = "是否公开:0-否 1-是")
    private String isOpen;

    //递归校验
    //@Valid
    //@NotEmpty(message = "属性值集合不能为空")
    @Schema(description = "属性值集合")
    private List<AlbumAttributeValueVo> albumAttributeValueVoList;

    @NotEmptyPaid(message = "价格类型不能为空")
    public String getPayTypeAndPriceType() {
        return this.getPayType() + "_" + this.getPriceType();
    }

    @NotEmptyPaid(message = "价格不能为空")
    public String getPayTypeAndPrice() {
        return this.getPayType() + "_" + this.getPrice();
    }
}

在 sql 里面查关联表。

不同维度,你是4 行,但是我想要 1593 的4列属性,最后封装在一个Vo实体类中

sql 复制代码
select
    album_info.id as albumId,
    album_info.album_title,
    album_info.cover_url,
    album_info.include_track_count,
    album_info.is_finished,

    album_info.status,
    album_stat.stat_num,
    album_stat.stat_type

from album_info

inner join album_stat
on album_stat.album_id=album_info.id
where album_info.user_id = 19;

对于同一个albumId应该所有的属性在一行中,所以我们对他们进行分组一下

但是分组是有要求的:

分组划分的这一列必须是表的主键,不是就爆炸

这里首先以单个表来演示:

sql 复制代码
select
    album_info.id as albumId,
    album_info.album_title

from album_info
where album_info.user_id = 19
group by album_info.id;

如果不是主键列进行分组

sql 复制代码
select
    album_info.id as albumId,
    album_info.album_title

from album_info
where album_info.user_id = 19
group by album_info.user_id;

按照分组的列查询,但是如果有的了后面任意

sql 复制代码
select
    album_info.user_id
这加其他列也一样报错

from album_info
where album_info.user_id = 19
group by album_info.user_id;

分组的规则:

mysql5.7 后有一种模式,sql规范的模式:sql_mode,其中涉及到分组

单表

分组是主键,select 后面可以跟这个表中的任意列

不是主键 select 只能跟上分组的列,以及其他列的聚合函数处理后的结果

多表

即使是主键分组,依然需要聚合函数处理

这个跟了主键,但是加了聚合函数是成功了

sql 复制代码
select
    album_info.user_id,
    count(album_info.id)
from album_info
where album_info.user_id = 19
group by album_info.user_id;

那如果是多表呢?做聚合函数

这里是个多表,哪怕是主键,后面有其他表,依然得用聚合函数!

那怎么去映射呢 4 行变 4列

我们这里用到了一个 if 函数,最后还是套聚合函数!

sql 复制代码
select
    album_info.id as albumId,
    album_info.album_title,
    album_info.cover_url,
    album_info.include_track_count,
    album_info.is_finished,
    album_info.status,
    count(if(album_stat.stat_type='0401', album_stat.stat_num, 0)) as playStatNum

from album_info

inner join album_stat
on album_stat.album_id=album_info.id
where album_info.user_id = 19
group by album_info.id;

这里只是显现了一行,但是如果 4 行转化也是同样的

因为要做一个分页,我们再进行一个排序。

sql 复制代码
order by album_info.update_time desc
编码实现

转到 mapper.xml 中写 sql,对写的sql 进行一个简单的更改

这里没去校验 userId 是因为这个前面使用了 TingshuLogin,不登录肯定不行

AlbumInfoMapper

XML 复制代码
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//ibatis.apache.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">


<mapper namespace="com.anran.tingshu.album.mapper.AlbumInfoMapper">

    <select id="findUserAlbumPage" resultType="com.anran.tingshu.vo.album.AlbumInfoVo">
        select
            album_info.id as albumId,
            album_info.album_title,
            album_info.cover_url,
            album_info.include_track_count,
            album_info.is_finished,
            album_info.status,
            max(if(album_stat.stat_type='0401', album_stat.stat_num, 0)) as playStatNum,
            max(if(album_stat.stat_type='0402', album_stat.stat_num, 0)) as subscribeStatNum,
            max(if(album_stat.stat_type='0403', album_stat.stat_num, 0)) as buyStatNum,
            max(if(album_stat.stat_type='0404', album_stat.stat_num, 0)) as commentsStatNum

        from album_info
        inner join album_stat
        on album_stat.album_id=album_info.id
        <where>
            <if test="vo.albumTitle != null and vo.albumTitle != ''">
                and album_info.album_title=#{vo.albumTitle}
            </if>
            <if test="vo.status != null and vo.status != ''">
                and album_info.status=#{vo.status}
            </if>
            and album_info.user_id=#{vo.userId} and album_info.is_deleted=0
        </where>
        group by album_info.id
        order by album_info.update_time desc
    </select>
</mapper>
  • 因为不需要自定义数据,在 sql 方面完成了封装,所以不需要 mybatis 封装 ,所以直接返回值就是resultType而不是resultMap
相关推荐
爱可生开源社区1 天前
2026 年,优秀的 DBA 需要具备哪些素质?
数据库·人工智能·dba
随逸1772 天前
《从零搭建NestJS项目》
数据库·typescript
加号32 天前
windows系统下mysql多源数据库同步部署
数据库·windows·mysql
シ風箏2 天前
MySQL【部署 04】Docker部署 MySQL8.0.32 版本(网盘镜像及启动命令分享)
数据库·mysql·docker
李慕婉学姐2 天前
Springboot智慧社区系统设计与开发6n99s526(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。
数据库·spring boot·后端
百锦再2 天前
Django实现接口token检测的实现方案
数据库·python·django·sqlite·flask·fastapi·pip
tryCbest2 天前
数据库SQL学习
数据库·sql
jnrjian2 天前
ORA-01017 查找机器名 用户名 以及library cache lock 参数含义
数据库·oracle
十月南城2 天前
数据湖技术对比——Iceberg、Hudi、Delta的表格格式与维护策略
大数据·数据库·数据仓库·hive·hadoop·spark
Henry Zhu1232 天前
数据库:并发控制基本概念
服务器·数据库