在合并查询中,尤其是二分类的情况,在查询结果是相同列名的时候可以考虑合并查询。先查询出行的结果,再使用union或者union all合并查询结果。

另外如果 union 和 order by 一起使用的话要注意使用方法。

一、适用场景和方法

(1)适用场景

考虑查询过程中是否存在以下情况:

  • 查询行时用的表不同;

  • 查询某些行时需要where条件,某些行不需要where条件;

  • 分类查询;

  • 查询的结果具有相同的列名。

存在上述情况时,大多数需要合并查询。先分行查询,再将查询出的行合并到一个表中。

(2)方法

MySQL合并查询,将查询到的行(具有相同列)合并到一个表中使用union或者union all函数

具体包括:

函数 使用说明
union 出现相同行时,不保留重复行,进行去重处理
union all 出现相同行时,保留重复行,不进行去重

根据查询需要使用不同合并函数。

二、案例分析

下面用2个具体的案例(由简到难)来说明行合并的过程:

(1)简单案例

案例来自:SQL26 计算25岁以上和以下的用户数量

描述

现在运营想要将用户划分为25岁以下和25岁及以上两个年龄段,分别查看这两个年龄段用户数量

本题注意:age为null 也记为 25岁以下

示例:user_profile

id device_id gender age university gpa active_days_within_30 question_cnt answer_cnt
1 2138 male 21 北京大学 3.4 7 2 12
2 3214 male 复旦大学 4 15 5 25
3 6543 female 20 北京大学 3.2 12 3 30
4 2315 female 23 浙江大学 3.6 5 1 2
5 5432 male 25 山东大学 3.8 20 15 70
6 2131 male 28 山东大学 3.3 15 7 13
7 4321 male 26 复旦大学 3.6 9 6 52

根据示例,你的查询应返回以下结果:

age_cut number
25岁以下 4
25岁及以上 3

【分类】:合并查询、多表连接

分析思路

难点:

1.单个字符或者值可以作为一列:例如'activity2' as activity

2.用了一半时间就完成高难度试卷。两个时间相减得到分钟:timestampdiff(minute, date_expr1, date_expr2) 两个时间的差

(1)统计25岁以下学生的人数

​ [条件]:where score >= 85 and year(start_time) = 2021

​ [使用]:distinct。一定要去重

(2)统计25岁以上学生的人数

​ [条件]:where difficulty = 'hard' and score > 80 and year(start_time) = 2021 and timestampdiff(minute, start_time, submit_time) < duration / 2

​ [使用]:多表连接使用 join using( )

(3)合并两个表

​ [使用]:union all 和union 都可以,因为列activity不会有重复。

最终结果

(
select 查询结果 [年龄段; 人数]
from 从哪张表中查询数据[用户表]
where 查询条件 [年龄小于25或者为空]
)
union
(
select 查询结果 [年龄段; 人数]
from 从哪张表中查询数据[用户表]
where 查询条件 [年龄大于25]
)

该题的多种解法详见:SQL26 计算25岁以上和以下的用户数量

求解代码

union

(
#统计25岁以下学生的人数
select
'25岁以下' as age_cut,
count(device_id) as number
from user_profile
where age < 25 or age is null
)
union
(
#统计25岁以上学生的人数
select
'25岁及以上' as age_cut,
COUNT(device_id) as number
from user_profile
where age >= 25
)

(2)较难案例

案例来自:SQL132 每个题目和每份试卷被作答的人数和次数

描述

现有试卷作答记录表exam_record(uid用户ID, exam_id试卷ID, start_time开始作答时间, submit_time交卷时间, score得分):

id uid exam_id start_time submit_time score
1 1001 9001 2021-09-01 09:01:01 2021-09-01 09:41:01 81
2 1002 9002 2021-09-01 12:01:01 2021-09-01 12:31:01 70
3 1002 9001 2021-09-01 19:01:01 2021-09-01 19:40:01 80
4 1002 9002 2021-09-01 12:01:01 2021-09-01 12:31:01 70
5 1004 9001 2021-09-01 19:01:01 2021-09-01 19:40:01 85
6 1002 9002 2021-09-01 12:01:01 (NULL) (NULL)

题目练习表practice_record(uid用户ID, question_id题目ID, submit_time提交时间, score得分):

id uid question_id submit_time score
1 1001 8001 2021-08-02 11:41:01 60
2 1002 8001 2021-09-02 19:30:01 50
3 1002 8001 2021-09-02 19:20:01 70
4 1002 8002 2021-09-02 19:38:01 70
5 1003 8001 2021-08-02 19:38:01 70
6 1003 8001 2021-08-02 19:48:01 90
7 1003 8002 2021-08-01 19:38:01 80

请统计每个题目和每份试卷被作答的人数和次数,分别按照"试卷"和"题目"的uv & pv降序显示,示例数据结果输出如下:

tid uv pv
9001 3 3
9002 1 3
8001 3 5
8002 2 2

解释:“试卷”有3人共练习3次试卷9001,1人作答3次9002;“刷题”有3人刷5次8001,有2人刷2次8002

【分类】:合并查询

分析思路

难点:

  1. union 和 order by 一起使用需要注意的问题

(1)统计每份试卷被作答的人数和次数

​ [条件]:where score >= 85 and year(start_time) = 2021

​ [使用]:distinct。一定要去重

(2)统计每个题目被作答的人数和次数

​ [条件]:where difficulty = 'hard' and score > 80 and year(start_time) = 2021 and timestampdiff(minute, start_time, submit_time) < duration / 2

​ [使用]:多表连接使用 join using( )

(3)合并两个表,分别按照"试卷"和"题目"的uv & pv降序显示

​ [使用]:union all 和union 都可以,因为列activity不会有重复。

最终结果

select * from
(
select 查询结果 [试卷ID; 作答次数]
from 从哪张表中查询数据[试卷作答记录表]
group by 分组条件 [试卷ID]
order by 对查询结果排序 [按照"试卷"的uv & pv降序]
)
union
select * from
(
select 查询结果 [题目ID; 作答次数]
from 从哪张表中查询数据[题目练习表]
group by 分组条件 [题目ID]
order by 对查询结果排序 [按照"题目"的uv & pv降序]
)

求解代码

方法一:

#正确代码
select * from
(
select
exam_id as tid,
count(distinct uid) as uv,
count(uid) as pv
from exam_record a
group by exam_id
order by uv desc, pv desc
) a
union
select * from
(
select
question_id as tid,
count(distinct uid) as uv,
count(uid) as pv
from practice_record b
group by question_id
order by uv desc, pv desc
) attr

是不是可以union两个子句之后再使用order by ? 但是这个排序要对2个表分别进行降序,就需要写成下面这样:

方法二:

使用函数

left(str,length) 函数: str左边开始的长度为 length 的子字符串,在本例中为‘9’和‘8’

解释:试卷编号以‘9’开头、题目编号以‘8’开头,对编号进行降序就是对"试卷"和"题目"分别进行排序

(
#每份试卷被作答的人数和次数
select
exam_id as tid,
count(distinct uid) as uv,
count(*) as pv
from exam_record
group by exam_id
)
union
(
#每个题目被作答的人数和次数
select
question_id as tid,
count(distinct uid) as uv,
count(*) as pv
from practice_record
group by question_id
)
#分别按照"试卷"和"题目"的uv & pv降序显示
order by left(tid,1) desc,uv desc,pv desc

推荐使用方法一,更具有普适性。

扩展:

前往查看MySQL union 和 order by 一起使用需要注意的问题

MySQL 合并查询union 查询出的行合并到一个表中的更多相关文章

  1. exp导出一个表中符合查询条件的数据

    原文地址:exp导出一个表中符合查询条件的数据 作者:charsi 导出一个表中的部分数据,使用QUERY参数,如下导出select * from test where object_id>50 ...

  2. ORACLE 查询一个数据表后通过遍历再插入另一个表中的两种写法

    ORACLE 查询一个数据表后通过遍历再插入另一个表中的两种写法 语法 第一种: 通过使用Oracle语句块  --指定文档所有部门都能查看 declare cursor TABLE_DEPT and ...

  3. Linq 中查询一个表中指定的字段

    //Linq中查询一个表中指定的几个字段: ); // FindAllItems()为查询对应表的所有数据的方法: // Where 里面为查询条件 // Select 为查询的筛选条件 new{} ...

  4. 对一个表中所有列数据模糊查询adoquery

    如何用adoquery对一个表中所有列进行模糊查询: procedure TForm3.Button4Click(Sender: TObject); var ASql,AKey: string; I: ...

  5. SQL查询一个表中类别字段中Max()最大值对应的记录

      SQL查询一个表中类别字段中Max()最大值对应的记录 SELECT A.id, A.name, A.version FROM   DOC A, (SELECT id, MAX(version)  ...

  6. 如何使用MySQL一个表中的字段更新另一个表中字段

    [本文出自:https://www.jb51.net/article/150323.htm] 这篇文章主要介绍了如何使用MySQL一个表中的字段更新另一个表中字段,需要的朋友可以参考下 1,修改1列 ...

  7. 获取一个表中的字段总数(mysql) Navicat如何导出Excel格式表结构 获取某个库中的一个表中的所有字段和数据类型

    如何获取一个表中的字段总数 1.function show columns from 表明: 结果 : 2.functiuon select count(*) from INFORMATION_SCH ...

  8. sql一个表中两个字段合并求和

    sql一个表中两个字段,合并求和 SELECT SUM(字段a+'.'+字段b) as total  from TABLE

  9. mysql从一个表中拷贝数据到另一个表中sql语句

    这一段在找新的工作,今天面试时,要做一套题,其中遇到这么一句话,从一个表中拷贝所有的数据到另一个表中的sql是什么? 原来我很少用到,也没注意过这个问题,面试后我上网查查,回来自己亲手写了写,测试了下 ...

  10. mysql中把一个表的数据批量导入另一个表中

    mysql中把一个表的数据批量导入另一个表中   不管是在网站开发还是在应用程序开发中,我们经常会碰到需要将MySQL或MS SQLServer某个表的数据批量导入到另一个表的情况,甚至有时还需要指定 ...

随机推荐

  1. 2流高手速成记(之六):从SpringBoot到SpringCloudAlibaba

    咱们接上回 2流高手速成记(之五):Springboot整合Shiro实现安全管理 - 14号程序员 - 博客园 (cnblogs.com) 身边常有朋友说:小项目用PHP.大项目用Java(这里绝无 ...

  2. iptables综合实验: 两个私有网络的互相通迅

    环境准备: 主机A IP:192.168.0.6/24 网关改为192.168.0.8 firewallA IP:eth1 192.168.0.8/24 eth0 10.0.0.8/24 删除默认路由 ...

  3. pod(五):pod hook(pod钩子)和优雅的关闭nginx pod

    目录 一.系统环境 二.前言 三.pod hook(pod钩子) 四.如何优雅的关闭nginx pod 一.系统环境 服务器版本 docker软件版本 Kubernetes(k8s)集群版本 CPU架 ...

  4. ES6 学习笔记(六)基本类型String

    字符串String 1.字面量 需要注意的地方: 由单引号或双引号括起来的字符序列. 单双引号可以嵌套,由最外围引号定界字符串 字符串字面量可以拆分成数行,每行必须以反斜线(\)结束,且反斜线都不计入 ...

  5. Codeforces Global Round 18 B. And It's Non-Zero(按位前缀和)

    题目大意:求一段数(l到r)的按位与结果不为零需要删除中间元素的最小个数 思路:按位与使得结果不为0只要有某一位全是1即可,所以只要统计每一位1的个数,用总个数减去1的个数就是某一位0的个数 删除包含 ...

  6. November 练习(Tou Xue)打卡

    Flag:NOIP前偷100道 \(\text{CF }1600\sim 2000+\) \(\text{or}\) \(\text{At } 1200\sim 1800+\) \(\text{or} ...

  7. 【lvgl】01-lvgl移植之在linux上跑

    目录 前言 linux安装SDL2 官方推荐 移植lvgl v8.0 目录框架 拉取lvgl 添加lv_conf.h和lv_drv_conf.h配置文件 lv_conf.h lv_drv_conf.h ...

  8. eBPF 实践 -- 网络可观测

    简介 观测云采集器,是一款开源.一体式的数据采集 Agent,它提供全平台操作系统支持,拥有全面数据采集能力,涵盖基础设施.指标.日志.应用性能.用户访问以及安全巡检等各种场景.通过 eBPF 技术的 ...

  9. PyTorch Geometric Temporal 介绍 —— 数据结构和RGCN的概念

    Introduction PyTorch Geometric Temporal is a temporal graph neural network extension library for PyT ...

  10. 【每日一题】【链表&头插法&ASCII码】【链表&迭代器】2022年1月28日-NC1 大数加法

    描述以字符串的形式读入两个数字,编写一个函数计算它们的和,以字符串形式返回. 思路:原生链表&头插法节点值 import java.util.*; public class Solution ...