900字范文,内容丰富有趣,生活中的好帮手!
900字范文 > postgres sql 多表联合查询_从零学会SQL-多表查询

postgres sql 多表联合查询_从零学会SQL-多表查询

时间:2021-10-23 23:28:20

相关推荐

postgres sql 多表联合查询_从零学会SQL-多表查询

之前学习的内容几乎针对单个表进行简单操作,实际工作中可没有这么简单,复杂的表结构和多表数据关联进行分析,这时候需要我们掌握多表查询方法,一如既往,我们先看一下这篇的主要内容:

表的加法表的联结联结应用案例case表达式

下面我们就来一一攻克吧。

一、表的加法

表达加法针对于两张相同数据结构不同数据的操作

首先,原student数据库中course表数据如下:

其次,我们在student数据库中新增course1表,新添数据如下:

最后,我们用表的加法,来把这两张表中的数据组合在一起。表的加法,我们要用UNION来实现。

UNION的作用 UNION运算符用于组合两个或更多SELECT语句的结果集

UNION使用前提两个表或多表必须具有相同的列数,数据类型

A. UNION 语法

SELECT column_name(s) FROM table1UNIONSELECT column_name(s) FROM table2;

我们把以上两张课程表course和couser1,用表加法UNION合并:

SELECT 课程号,课程名称from courseUNIONselect 课程号,课程名称FROM course1;

从结果表中可以看到,course和course1两张表中不同的数据合并在一起了,两张表中重复的数据,SQL会把重复值删除,只保留一个值。

如果允许重复值,请使用UNION ALL。

B.UNION ALL

若保留两个表或多表所有列的数据,用UNION ALL

SELECT column_name(s) FROM table1UNION ALLSELECT column_name(s) FROM table2;

※ 注:UNION结果集中的列名总是等于UNION中第一个SELECT语句中的列名。

SELECT 课程号,课程名称from courseUNION ALLselect 课程号,课程名称FROM course1;

如结果所示,两个表中的共有的数据“0001,语文”的重复数据都被保留下来了。

二、表的联结

关系型数据库是由多张表组成的,如数据库student下有四张表,他们之间关系如下:

我们来看student表和score表两表之间的关系,两张表就是通过学号这个主键关联起来的。假如我想知道学号为0001的学生的成绩是多少,我就可以在score表中查找到学号为0001的学生的课程号和成绩(一共有3行数据)。

所以关系就是表之间对应的匹配(根据主键),在关系型数据库中,这种关系的学名叫做联结(join)。

A. JOIN连接的作用

JOIN 连接用于把来自两个或多个表的行结合起来,基于这些表之间的共同字段。

常用的联结如下:

CROSS JOIN(交叉联结):没有条件的join,返回被连接的两个表所有数据行的笛卡尔积;INNER JOIN(内联结):如果表中有至少一个匹配,则返回行;LEFT JOIN(左联结):即使右表中没有匹配,也从左表返回所有的行;RIGHT JOIN(右联结):即使左表中没有匹配,也从右表返回所有的行;FULL JOIN(全联结):只要其中一个表中存在匹配,则返回行。

B. CROSS JOIN(交叉联结)

将表中的每一行与另一张表的每一行联结一起。返回到的数据行数等于第一个表中符合查询条件的数据行数乘以第二个表中符合查询条件的数据行数。

SELECT * FROM A CROSS JOIN B

交叉联结在实际工作中运用的比较少,因为返回的结果行数太多了,表太大,计算量大,效率非常低,不建议使用。但交叉联结是所有联结的基础,接下来学习的几种联结都是在交叉联结的基础上加了特定的条件。

C. INNER JOIN(内联结)

将两个表或多表数据重复数据返回,从多个表中返回满足 JOIN 条件的所有行,语法如下

SELECT column_name(s)FROM table1INNER JOIN table2 ON table1.column_name = table2.column_name;

栗子,result1学生表和result成绩表联结

重复数据为学号0001、0002、0003,inner join将两表都有的数据联合:

SELECT a.学号,a.姓名,b.课程号,b.成绩 -- 3 取出表a的学号、姓名列,取出b表的课程号、成绩两列。from student as a INNER JOIN score AS b -- 1 同时使用两张表,并重命名ona.学号=b.学号; -- 2 两个表的联结条件

最后两表数据联合如下:

D. LEFT JOIN(左联结)

SQL左链接LEFT JOIN关键字将左侧表作为主表,返回左表(表1)中的所有行,即使在右表(表2)中没有匹配。如果在正确的表中没有匹配,结果是NULL。

SELECT column_name(s)FROM table1LEFT JOIN table2ON table1.column_name=table2.column_name;

栗子:查询学生表中所有学生的课程号和成绩

SELECT a.学号,a.姓名,b.课程号,b.成绩from student as a LEFT JOIN score AS bONa.学号=b.学号;

我们发现学号0004、0005没有对应的课程号和成绩,没有匹配上他们的信息,返回值为NULL。

E. RIGHT JOIN(右联结)

SQL右链接 RIGHT JOIN 关键字返回右表(table2)的所有行,即使在左表(table1)上没有匹配。如果左表没有匹配,则结果为NULL。

SELECT column_name(s) FROM table1RIGHT JOIN table2 ON table1.column_name = table2.column_name;

栗子:将学生表和成绩表进行右连接

SELECT a.学号,a.姓名,b.课程号,b.成绩from student as a RIGHT JOIN score AS bONa.学号=b.学号;

我们从上面可以看出,在score表里没有学号0004和0005的成绩,所以联结后没有他们信息。

F. FULL JOIN(全联结)

当左(表1)或右(表2)表记录匹配时,FULL OUTER JOIN关键字将返回所有记录。注意:FULL OUTER JOIN可能会返回非常大的结果集!且MySQL不支持全联结。但可以通过union来实现。

SELECT column_name(s) FROM table1FULL OUTER JOIN table2 ON table1.column_name = table2.column_name;mysql> select * from A left join B on B.name = A.name -> union -> select * from A right join B on B.name = A.name;

三、联结应用案例

再开始案例实操之前再回忆一下用SQL解决业务问题的步骤,不要忘了哦!

a).把业务问题解读成通俗易懂的大白话;

b).写出分析思路(按步骤分解);

c).写出对应的SQL子句。

A.栗子:查询所有学生的学号、姓名、选课数、总成绩。

a).把业务问题解读成通俗易懂的大白话:

查询学生的学号、姓名;和对每个学生所选的课程号计数;并对每个学生的成绩求和。

b).写出分析思路(按步骤分解):

提取关键字:学号,姓名,选课数,总成绩学生姓名、学号——>student表选课数——>每个学生的选课数:score表,按学号分组group by,并对课程号计数count总成绩——>每个学生的总成绩:score表,按学号分组group by,并对成绩求和sum学生是查询主体,student 和score表通过学号联结,且为左联结。

c).写出对应的SQL子句:

SELECT s1.学号,s1.姓名,count(课程号) as 选课数,SUM(成绩) as 总成绩from student as s1 LEFT JOIN score AS s2ONs1.学号=s2.学号GROUP BY s1.学号;

B.栗子:查询平均成绩大于85的所有学生的学号,姓名和平均成绩

a).把业务问题解读成通俗易懂的大白话:

查询学生的学号、姓名、平均成绩;选出学生的平均值成绩,大于85的数据。

b).写出分析思路(按步骤分解):

提取关键字:学号,姓名,平均成绩学生姓名、学号——>student表平均成绩——>每个学生的平均成绩:score表,按学号分组group by,并求对成绩求平均值avg学生是查询主体,student 和score表通过学号联结,且为左联结。

c).写出对应的SQL子句:

SELECT s1.学号,s1.姓名,AVG(s2.成绩) as 平均成绩from student as s1 LEFT JOIN score AS s2ONs1.学号=s2.学号GROUP BY s1.学号HAVING 平均成绩>85;

C. 栗子:查询学生的选课情况:学号,姓名,课程号,课程名称

a).把业务问题解读成通俗易懂的大白话:

查询学生的学号、姓名、课程号,课程名称。

b).写出分析思路(按步骤分解):

提取关键字:学号、姓名、课程号,课程名称学生姓名、学号——>student表课程号,课程名称——>course表课程号——>引入score表。因为student表和course表没有共同关键字,借助score表联结学生是查询主体,student 和score表通过学号左联结,score表和course表通过课程号左联结。

c).写出对应的SQL子句:

SELECT s1.学号,s1.姓名,c1.课程号,c1.课程名称from student as s1 INNER JOIN score AS s2ONs1.学号=s2.学号INNER JOIN course as c1ONs2.课程号=c1.课程号;

四、case表达式

case表达式帮助我们处理负责的SQL语句,case的使用就是条件判断,类似于我们常用的if else。

CASE具有两种格式,简单CASE函数和CASE搜索函数。这两种方式,大部分情况下可以实现相同的功能。

简单case函数

CASE column WHEN <condition> THEN value WHEN <condition> THEN value......ELSE value END

CASE搜索函数

CASE WHEN <condition> [,<condition>] THEN value WHEN <condition> [,<condition>] THEN value......ELSE valueEND

A.栗子:判断学生的成绩是否及格(>=60及格,<60不及格)

case表达式运行顺序如下:

SELECT 学号,课程号,成绩,(CASE when 成绩>=60 then '及格'when 成绩<60 then '不及格'else NULLend ) as 是否及格from score;

上面的case语句执行逻辑:若第一个WHEN子句为真,则CASE表达式的真假值判断就会中止,执行then语句中的命令,而剩余的WHEN子句会被忽略。若第一个WHEN子句为假值,则执行第二个WHEN子句,以此类推。如果所有的WHEN子句均为假值,则执行ELSE子句。

B. 栗子:查询出每门课程的及格人数和不及格人数

SELECT 课程号,SUM(CASE when 成绩>=60 then 1else 0end) as 及格人数,SUM(CASE when 成绩<60 then 1else 0end)as 不及格人数from scoreGROUP BY 课程号;

运行顺序如下:

先运行group by对数据进行分组,再运行case表达式,得到每一行的及格人数:如果这一行的成绩>=60,就将这一行的及格人数值设置为1,否则则设置为0。表示这一行及格人数为1,不及格人数为0;最后通过sum函数,对及格人数进行求和,同理可得不及格人数。

C. 栗子:使用分段{100-85}、{85-70}、{70-60},{<60}来统计各科成绩,根据课程号、课程名称统计各分段人数。

a).把业务问题解读成通俗易懂的大白话:

按课程号和课程名称分组,成绩分段在{100-85}、{85-70}、{70-60},{<60}的分别有多少人。

b).写出分析思路(按步骤分解):

提取关键字:课程号、课程名称、各分段成绩课程号,课程名称——>course表课程号、成绩——>score表课程(课程号、课程名称)是查询主体,course表和score表通过课程号右联结成绩分为{100-85}、{85-70}、{70-60},使用case语句。各科成绩——>根据课程号/课程名称进行常规分组,group by语句。

c).写出对应的SQL子句:

SELECT s1.课程号,c1.课程名称,sum(case when 成绩 between 85 and 100 then 1else 0end ) as '{100,85}',sum(case when 成绩 between 70 and 85 then 1else 0end ) as '{85,70}',sum(case when 成绩 between 60 and 70 then 1else 0end ) as '{70,60}',sum(case when 成绩 < 60 then 1else 0end ) as '{<60}'from course as c1 RIGHT JOIN score as s1ONc1.课程号=s1.课程号GROUP BY s1.课程号,c1.课程名称;

这里面需要注意的是凡是在group by后面出现的字段,必须同时在select后面出现;凡是在select后面出现的、同时未在聚合函数中出现的字段,必须同时出现在group by后面。

欢迎来到SQLZOO开始今天的练习:

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。