DTO:

  1. /**
  2. * 员工考试记录表
  3. * @author lichao sunlightcs@gmail.com
  4. * @since 3.0 2021-04-09
  5. */
  6. @Data
  7. @ApiModel(value = "员工考试记录表")
  8. public class TabrExamRecordCompleteDTO implements Serializable {
  9. private static final long serialVersionUID = 1L;
  10. @ApiModelProperty(value = "主键")
  11. private Long id;
  12. @ApiModelProperty(value = "考试名称")
  13. private String examName;
  14. @ApiModelProperty(value = "考试表id")
  15. private Long examId;
  16. @ApiModelProperty(value = "考生id")
  17. private Long creator;
  18. @ApiModelProperty(value = "考生姓名")
  19. private String creatorName;
  20. @ApiModelProperty(value = "报名时间")
  21. private Date createDate;
  22. @ApiModelProperty(value = "是否完成考试 0-未完成 1-已完成")
  23. private Integer completeFlag;
  24. @ApiModelProperty(value = "考试类型")
  25. private Integer examType;
  26. @ApiModelProperty(value = "考试开始时间")
  27. private Date startTime;
  28. @ApiModelProperty(value = "考试结束时间")
  29. private Date endTime;
  30. @ApiModelProperty(value = "考试耗时")
  31. private Integer estimateTime;
  32. @ApiModelProperty(value = "考试成绩")
  33. private String score;
  34. }

Controller:

  1. @GetMapping("getCompleteRecord")
  2. @ApiOperation("考生获取自己已完成的考试")
  3. @LogOperation("考生获取自己已完成的考试")
  4. @ApiImplicitParams({
  5. @ApiImplicitParam(name = Constant.PAGE, value = "当前页码,从1开始", paramType = "query", required = true, dataType="int") ,
  6. @ApiImplicitParam(name = Constant.LIMIT, value = "每页显示记录数", paramType = "query",required = true, dataType="int") ,
  7. @ApiImplicitParam(name = Constant.ORDER_FIELD, value = "排序字段", paramType = "query", dataType="String") ,
  8. @ApiImplicitParam(name = Constant.ORDER, value = "排序方式,可选值(asc、desc)", paramType = "query", dataType="String"),
  9. @ApiImplicitParam(name = "examName", value = "根据考试名称模糊搜索", paramType = "query", dataType="String"),
  10. @ApiImplicitParam(name = "examType", value = "根据考试类型检索,0-业务考试,1-桌面推演,2-体能测试", paramType = "query", dataType="int")
  11. })
  12. public Result<PageData<TabrExamRecordCompleteDTO>> getCompleteRecord(@ApiIgnore @RequestParam Map<String, Object> params) {
  13. //题目的分页数据
  14. PageData<TabrExamRecordCompleteDTO> page = tabrExamRecordService.getCompleteRecord(params);
  15. return new Result<PageData<TabrExamRecordCompleteDTO>>().ok(page);
  16. }

Service:

  1. PageData<TabrExamRecordCompleteDTO> getCompleteRecord(Map<String, Object> params);

Impl:

  1. @Override
  2. public PageData<TabrExamRecordCompleteDTO> getCompleteRecord(Map<String, Object> params) {
  3. //分页
  4. Page<TabrExamRecordCompleteDTO> page1 =new Page<>(Long.parseLong(params.get("page").toString()),Long.parseLong(params.get("limit").toString()));
  5. //用户信息
  6. UserDetail user = SecurityUser.getUser();
  7. //模糊搜索
  8. String examName = null;
  9. if (params.get("examName") != null) {
  10. examName = params.get("examName").toString();
  11. }
  12. //考试类型检索
  13. Integer examType = null;
  14. if (params.get("examType") != null) {
  15. examType = Convert.toInt(params.get("examType"));
  16. }
  17. //查询
  18. IPage<TabrExamRecordCompleteDTO> page = baseDao.selectCompleteRecord(
  19. page1,
  20. user.getId(),
  21. examName,
  22. examType
  23. );
  24. return getPageData(page, TabrExamRecordCompleteDTO.class);
  25. }

Dao:

  1. /**
  2. * 获取考生已完成的考试
  3. * @author WHN
  4. * @date 2021/4/16 10:44
  5. */
  6. IPage<TabrExamRecordCompleteDTO> selectCompleteRecord(Page<TabrExamRecordCompleteDTO> page1, Long userid, String examName,Integer examType);

xml:

  1. <select id="selectCompleteRecord" resultType="io.renren.dto.TabrExamRecordCompleteDTO">
  2. <if test="param4 == null or param4 == 0">
  3. select r.id,
  4. r.exam_name,
  5. r.exam_id,
  6. r.creator,
  7. r.complete_flag,
  8. r.exam_type,
  9. u.real_name creator_name,
  10. e.start_time,
  11. e.end_time,
  12. e.estimate_time,
  13. (select group_concat(b.score) from tabr_exam_record_busi b where b.exam_record_id = r.id) score,
  14. (select group_concat(b.create_date) from tabr_exam_record_busi b where b.exam_record_id = r.id) create_date
  15. from tabr_exam_record AS r
  16. LEFT JOIN sys_user u on r.creator = u.id
  17. LEFT JOIN tabr_exam e on r.exam_id = e.id
  18. where r.creator = #{userid}
  19. and r.complete_flag = 1
  20. and r.exam_type = 0
  21. <if test="param3 != null">
  22. and r.exam_name like "%"#{examName}"%"
  23. </if>
  24. </if>
  25. <if test="param4 == null">
  26. UNION
  27. </if>
  28. <if test="param4 == null or param4 == 1">
  29. select r.id,
  30. r.exam_name,
  31. r.exam_id,
  32. r.creator,
  33. r.complete_flag,
  34. r.exam_type,
  35. u.real_name creator_name,
  36. e.start_time,
  37. e.end_time,
  38. e.estimate_time,
  39. (select group_concat(p.score) from tabr_exam_record_plot p where p.exam_record_id = r.id) score,
  40. (select group_concat(p.create_date) from tabr_exam_record_plot p where p.exam_record_id = r.id) create_date
  41. from tabr_exam_record AS r
  42. LEFT JOIN sys_user u on r.creator = u.id
  43. LEFT JOIN tabr_exam e on r.exam_id = e.id
  44. where r.creator = #{userid}
  45. and r.complete_flag = 1
  46. and r.exam_type = 1
  47. <if test="param3 != null">
  48. and r.exam_name like "%"#{examName}"%"
  49. </if>
  50. </if>
  51. <if test="param4 == null">
  52. UNION
  53. </if>
  54. <if test="param4 == null or param4 == 2">
  55. select r.id,
  56. r.exam_name,
  57. r.exam_id,
  58. r.creator,
  59. r.complete_flag,
  60. r.exam_type,
  61. u.real_name creator_name,
  62. e.start_time,
  63. e.end_time,
  64. e.estimate_time,
  65. (select group_concat(h.score) from tabr_physical_exam_score h where h.exam_record_id = r.id) score,
  66. r.create_date create_date
  67. from tabr_exam_record AS r
  68. LEFT JOIN sys_user u on r.creator = u.id
  69. LEFT JOIN tabr_exam e on r.exam_id = e.id
  70. where r.creator = #{userid}
  71. and r.complete_flag = 1
  72. and r.exam_type = 2
  73. <if test="param3 != null">
  74. and r.exam_name like "%"#{examName}"%"
  75. </if>
  76. </if>
  77. </select>

Mysql表展示:

主表:tabr_exam_record,主表的id字段与其他三个表的exam_record_id字段关联

查询:LEFT JOIN UNION的一对三 一对多查询 - 图1

从表1:tabr_exam_record_busi

查询:LEFT JOIN UNION的一对三 一对多查询 - 图2

从表2:tabr_exam_record_plot

查询:LEFT JOIN UNION的一对三 一对多查询 - 图3

从表3:tabr_physical_exam_score

查询:LEFT JOIN UNION的一对三 一对多查询 - 图4

SQL测试:left join的sys_user表是用户信息表,对应主从表中的creator字段;left join的tabr_exam表是主表tabr_exam_record关联的上级表。

  1. select
  2. r.id, r.exam_name, r.exam_id, r.creator, r.complete_flag, r.exam_type, u.real_name creator_name, e.start_time, e.end_time, e.estimate_time,
  3. (select group_concat(b.score) from tabr_exam_record_busi b where b.exam_record_id = r.id) score,
  4. (select group_concat(b.create_date) from tabr_exam_record_busi b where b.exam_record_id = r.id) create_date
  5. from tabr_exam_record AS r
  6. LEFT JOIN sys_user u on r.creator = u.id
  7. LEFT JOIN tabr_exam e on r.exam_id = e.id
  8. where r.creator = 1357866375569235970
  9. and r.complete_flag = 1
  10. and r.exam_type = 0
  11. UNION
  12. select
  13. r.id, r.exam_name, r.exam_id, r.creator, r.complete_flag, r.exam_type, u.real_name creator_name, e.start_time, e.end_time, e.estimate_time,
  14. (select group_concat(b.score) from tabr_exam_record_plot b where b.exam_record_id = r.id) score,
  15. (select group_concat(b.create_date) from tabr_exam_record_plot b where b.exam_record_id = r.id) create_date
  16. from tabr_exam_record AS r
  17. LEFT JOIN sys_user u on r.creator = u.id
  18. LEFT JOIN tabr_exam e on r.exam_id = e.id
  19. where r.creator = 1357866375569235970
  20. and r.complete_flag = 1
  21. and r.exam_type = 1
  22. UNION
  23. select
  24. r.id, r.exam_name, r.exam_id, r.creator, r.complete_flag, r.exam_type, u.real_name creator_name, e.start_time, e.end_time, e.estimate_time,
  25. (select group_concat(b.score) from tabr_physical_exam_score b where b.exam_record_id = r.id) score,
  26. r.create_date create_date
  27. from tabr_exam_record AS r
  28. LEFT JOIN sys_user u on r.creator = u.id
  29. LEFT JOIN tabr_exam e on r.exam_id = e.id
  30. where r.creator = 1357866375569235970
  31. and r.complete_flag = 1
  32. and r.exam_type = 2

查询:LEFT JOIN UNION的一对三 一对多查询 - 图5

Swagger接口测试展示:

查询:LEFT JOIN UNION的一对三 一对多查询 - 图6
查询:LEFT JOIN UNION的一对三 一对多查询 - 图7

代码中用到的两个分页类:

  1. package com.baomidou.mybatisplus.extension.plugins.pagination;
  2. import com.baomidou.mybatisplus.core.metadata.IPage;
  3. import com.baomidou.mybatisplus.core.metadata.OrderItem;
  4. import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
  5. import java.util.ArrayList;
  6. import java.util.Arrays;
  7. import java.util.Collections;
  8. import java.util.Iterator;
  9. import java.util.List;
  10. import java.util.function.Predicate;
  11. import org.jetbrains.annotations.Nullable;
  12. public class Page<T> implements IPage<T> {
  13. private static final long serialVersionUID = 8545996863226528798L;
  14. protected List<T> records;
  15. protected long total;
  16. protected long size;
  17. protected long current;
  18. protected List<OrderItem> orders;
  19. protected boolean optimizeCountSql;
  20. protected boolean isSearchCount;
  21. protected boolean hitCount;
  22. public Page() {
  23. this.records = Collections.emptyList();
  24. this.total = 0L;
  25. this.size = 10L;
  26. this.current = 1L;
  27. this.orders = new ArrayList();
  28. this.optimizeCountSql = true;
  29. this.isSearchCount = true;
  30. this.hitCount = false;
  31. }
  32. public Page(long current, long size) {
  33. this(current, size, 0L);
  34. }
  35. public Page(long current, long size, long total) {
  36. this(current, size, total, true);
  37. }
  38. public Page(long current, long size, boolean isSearchCount) {
  39. this(current, size, 0L, isSearchCount);
  40. }
  41. public Page(long current, long size, long total, boolean isSearchCount) {
  42. this.records = Collections.emptyList();
  43. this.total = 0L;
  44. this.size = 10L;
  45. this.current = 1L;
  46. this.orders = new ArrayList();
  47. this.optimizeCountSql = true;
  48. this.isSearchCount = true;
  49. this.hitCount = false;
  50. if (current > 1L) {
  51. this.current = current;
  52. }
  53. this.size = size;
  54. this.total = total;
  55. this.isSearchCount = isSearchCount;
  56. }
  57. public boolean hasPrevious() {
  58. return this.current > 1L;
  59. }
  60. public boolean hasNext() {
  61. return this.current < this.getPages();
  62. }
  63. public List<T> getRecords() {
  64. return this.records;
  65. }
  66. public Page<T> setRecords(List<T> records) {
  67. this.records = records;
  68. return this;
  69. }
  70. public long getTotal() {
  71. return this.total;
  72. }
  73. public Page<T> setTotal(long total) {
  74. this.total = total;
  75. return this;
  76. }
  77. public long getSize() {
  78. return this.size;
  79. }
  80. public Page<T> setSize(long size) {
  81. this.size = size;
  82. return this;
  83. }
  84. public long getCurrent() {
  85. return this.current;
  86. }
  87. public Page<T> setCurrent(long current) {
  88. this.current = current;
  89. return this;
  90. }
  91. /** @deprecated */
  92. @Deprecated
  93. @Nullable
  94. public String[] ascs() {
  95. return CollectionUtils.isNotEmpty(this.orders) ? this.mapOrderToArray(OrderItem::isAsc) : null;
  96. }
  97. private String[] mapOrderToArray(Predicate<OrderItem> filter) {
  98. List<String> columns = new ArrayList(this.orders.size());
  99. this.orders.forEach((i) -> {
  100. if (filter.test(i)) {
  101. columns.add(i.getColumn());
  102. }
  103. });
  104. return (String[])columns.toArray(new String[0]);
  105. }
  106. private void removeOrder(Predicate<OrderItem> filter) {
  107. for(int i = this.orders.size() - 1; i >= 0; --i) {
  108. if (filter.test(this.orders.get(i))) {
  109. this.orders.remove(i);
  110. }
  111. }
  112. }
  113. public Page<T> addOrder(OrderItem... items) {
  114. this.orders.addAll(Arrays.asList(items));
  115. return this;
  116. }
  117. public Page<T> addOrder(List<OrderItem> items) {
  118. this.orders.addAll(items);
  119. return this;
  120. }
  121. /** @deprecated */
  122. @Deprecated
  123. public Page<T> setAscs(List<String> ascs) {
  124. return CollectionUtils.isNotEmpty(ascs) ? this.setAsc((String[])ascs.toArray(new String[0])) : this;
  125. }
  126. /** @deprecated */
  127. @Deprecated
  128. public Page<T> setAsc(String... ascs) {
  129. this.removeOrder(OrderItem::isAsc);
  130. String[] var2 = ascs;
  131. int var3 = ascs.length;
  132. for(int var4 = 0; var4 < var3; ++var4) {
  133. String s = var2[var4];
  134. this.addOrder(OrderItem.asc(s));
  135. }
  136. return this;
  137. }
  138. /** @deprecated */
  139. @Deprecated
  140. public String[] descs() {
  141. return this.mapOrderToArray((i) -> {
  142. return !i.isAsc();
  143. });
  144. }
  145. /** @deprecated */
  146. @Deprecated
  147. public Page<T> setDescs(List<String> descs) {
  148. if (CollectionUtils.isNotEmpty(descs)) {
  149. this.removeOrder((item) -> {
  150. return !item.isAsc();
  151. });
  152. Iterator var2 = descs.iterator();
  153. while(var2.hasNext()) {
  154. String s = (String)var2.next();
  155. this.addOrder(OrderItem.desc(s));
  156. }
  157. }
  158. return this;
  159. }
  160. /** @deprecated */
  161. @Deprecated
  162. public Page<T> setDesc(String... descs) {
  163. this.setDescs(Arrays.asList(descs));
  164. return this;
  165. }
  166. public List<OrderItem> orders() {
  167. return this.getOrders();
  168. }
  169. public List<OrderItem> getOrders() {
  170. return this.orders;
  171. }
  172. public void setOrders(List<OrderItem> orders) {
  173. this.orders = orders;
  174. }
  175. public boolean optimizeCountSql() {
  176. return this.optimizeCountSql;
  177. }
  178. public boolean isOptimizeCountSql() {
  179. return this.optimizeCountSql();
  180. }
  181. public boolean isSearchCount() {
  182. return this.total < 0L ? false : this.isSearchCount;
  183. }
  184. public Page<T> setSearchCount(boolean isSearchCount) {
  185. this.isSearchCount = isSearchCount;
  186. return this;
  187. }
  188. public Page<T> setOptimizeCountSql(boolean optimizeCountSql) {
  189. this.optimizeCountSql = optimizeCountSql;
  190. return this;
  191. }
  192. public void hitCount(boolean hit) {
  193. this.hitCount = hit;
  194. }
  195. public void setHitCount(boolean hit) {
  196. this.hitCount = hit;
  197. }
  198. public boolean isHitCount() {
  199. return this.hitCount;
  200. }
  201. }
  1. package com.baomidou.mybatisplus.core.metadata;
  2. import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
  3. import java.io.Serializable;
  4. import java.util.Iterator;
  5. import java.util.List;
  6. import java.util.Map;
  7. import java.util.function.Function;
  8. import java.util.stream.Collectors;
  9. public interface IPage<T> extends Serializable {
  10. /** @deprecated */
  11. @Deprecated
  12. default String[] descs() {
  13. return null;
  14. }
  15. /** @deprecated */
  16. @Deprecated
  17. default String[] ascs() {
  18. return null;
  19. }
  20. List<OrderItem> orders();
  21. default Map<Object, Object> condition() {
  22. return null;
  23. }
  24. default boolean optimizeCountSql() {
  25. return true;
  26. }
  27. default boolean isSearchCount() {
  28. return true;
  29. }
  30. default long offset() {
  31. return this.getCurrent() > 0L ? (this.getCurrent() - 1L) * this.getSize() : 0L;
  32. }
  33. default long getPages() {
  34. if (this.getSize() == 0L) {
  35. return 0L;
  36. } else {
  37. long pages = this.getTotal() / this.getSize();
  38. if (this.getTotal() % this.getSize() != 0L) {
  39. ++pages;
  40. }
  41. return pages;
  42. }
  43. }
  44. default IPage<T> setPages(long pages) {
  45. return this;
  46. }
  47. default void hitCount(boolean hit) {
  48. }
  49. default boolean isHitCount() {
  50. return false;
  51. }
  52. List<T> getRecords();
  53. IPage<T> setRecords(List<T> records);
  54. long getTotal();
  55. IPage<T> setTotal(long total);
  56. long getSize();
  57. IPage<T> setSize(long size);
  58. long getCurrent();
  59. IPage<T> setCurrent(long current);
  60. default <R> IPage<R> convert(Function<? super T, ? extends R> mapper) {
  61. List<R> collect = (List)this.getRecords().stream().map(mapper).collect(Collectors.toList());
  62. return this.setRecords(collect);
  63. }
  64. default String cacheKey() {
  65. StringBuilder key = new StringBuilder();
  66. key.append(this.offset()).append(":").append(this.getSize());
  67. List<OrderItem> orders = this.orders();
  68. if (CollectionUtils.isNotEmpty(orders)) {
  69. Iterator var3 = orders.iterator();
  70. while(var3.hasNext()) {
  71. OrderItem item = (OrderItem)var3.next();
  72. key.append(":").append(item.getColumn()).append(":").append(item.isAsc());
  73. }
  74. }
  75. return key.toString();
  76. }
  77. }