Java养成计划----学习打卡第六十七天
Java(打卡第六十七天)
MySQL数据库连接查询,distinct去重
> DBMS --> SQL ----> DB dbms是软件【数据库管理系统】,通过SQL 结构查询语言操作数据库database DB
distinct 查询结果去重
有的时候查询的结果有很多并且大量重复,这个时候就要使用distinct去重,使用的格式是将distinct加到去重字段前面 distinct different
SELECT DISTINCT col_name FROM table_name
这里演示一下
mysql> SELECT
-> DISTINCT CountryCode
-> FROM
-> city
-> WHERE
-> ID <= 100;
+-------------+
| CountryCode |
+-------------+
| AFG |
| NLD |
| ANT |
| ALB |
| DZA |
| ASM |
| AND |
| AGO |
| AIA |
| ATG |
| ARE |
| ARG |
+-------------+
12 rows in set (0.01 sec)
这个关键字有几个需要注意的地方
- 用distinct修饰的字段不能和普通的字段并列,会直接报错,因为数量不匹配
- distinct可以直接修饰很多的字段,Mysql的处理方法是将需要修饰的字段连接在一起,以整体为规模来去重
mysql> SELECT
-> DISTINCT Name,CountryCode
-> FROM
-> city
-> WHERE
-> ID <= 10;
+----------------+-------------+
| Name | CountryCode |
+----------------+-------------+
| Kabul | AFG |
| Qandahar | AFG |
| Herat | AFG |
| Mazar-e-Sharif | AFG |
| Amsterdam | NLD |
| Rotterdam | NLD |
| Haag | NLD |
| Utrecht | NLD |
| Eindhoven | NLD |
| Tilburg | NLD |
+----------------+-------------+
10 rows in set (0.00 sec)
比如这里就没有CONCAT(Name,CountryCode)就没有重复的内容,所以就还是10个
- COUNT 可以和DISTINCT一起使用,因为SELECT后面可以接分组函数,并且统计的就是去重后的所有数据
mysql> SELECT
-> COUNT(DISTINCT(CountryCode))
-> FROM
-> city
-> WHERE
-> ID <= 100;
+------------------------------+
| COUNT(DISTINCT(CountryCode)) |
+------------------------------+
| 12 |
+------------------------------+
1 row in set (0.01 sec)
和上面的数据是对应的
连接查询
从一张表中单独查询称为单表查询,
从多张表中联合起来查询数据,比如从a表中取name,从b表中取location,这种跨表查询,多张表联合查询数据,被称为连接查询
这里就以world数据库为例,三张表city,country,countrylanguage是有关系的,比如查询一个城市所处的大陆,就要同时借助city表和country表
连接查询的分类
根据语法的年代分类
- SQL92 : 1992年出现的语法
- SQL99: 1999年出现的语法
根据表连接的方式
这里来一个问题,当两张表的连接没有任何的限制,会发生什么事情
这里简单看一下这里的实验数据
+------+-------------+--------------+---------------+---------------+--------------+
| id | fruits_name | fruits_price | fruits_origin | fruits_remark | fruits_bonus |
+------+-------------+--------------+---------------+---------------+--------------+
| 1001 | 葡萄 | 3.7 | 山东 | 红香妃 | NULL |
| 1002 | 苹果 | 2.8 | 山东 | 红富士 | NULL |
| 1003 | 香蕉 | 6 | 海南 | 小芭蕉 | NULL |
+------+-------------+--------------+---------------+---------------+--------------+
3 rows in set (0.01 sec)
mysql> SELECT
-> *
-> FROM
-> culture;
+----------+----------+
| location | language |
+----------+----------+
| 四川 | 四川话 |
| 山东 | 山东话 |
| 海南 | 海南话 |
+----------+----------+
3 rows in set (0.00 sec)
先操作着两张数据少的表,再操作world库,这里比如 可以匹配每种水果产地的方言
SELECT
col_name1,col_name2
FROM
table_name1,table_name2;
这里col_name1是表table_name1中的,col_name2在table_name2中
mysql> SELECT
-> fruits_name,language
-> FROM
-> fruits,culture;
+-------------+----------+
| fruits_name | language |
+-------------+----------+
| 香蕉 | 四川话 |
| 苹果 | 四川话 |
| 葡萄 | 四川话 |
| 香蕉 | 山东话 |
| 苹果 | 山东话 |
| 葡萄 | 山东话 |
| 香蕉 | 海南话 |
| 苹果 | 海南话 |
| 葡萄 | 海南话 |
+-------------+----------+
9 rows in set (0.00 sec)
数据库中,是将第一张表中的每一行数据和第二张表的每一行数据匹配,所以这里如果不加限制,输出的是m*n行数据,也就是9行,并且没有达到搜索
笛卡尔积现象
当两张表进行连接查询时,没有任何条件限制,最终的查询结果条数,时两张表条数的乘积,这种现象就是笛卡尔积现象
所以要避免笛卡尔积现象,那么就要加上限制,比如这里就是要水果的产地和location相等的时候才匹配
//可以使用.来引用
basename.tablename.colname
//之前演示过不使用USE连接数据库,直接使用basename.tablename来查表
SELECT
col_name1,col_name2
FROM
table_name2,table_name2
WHERE
table_name1.col = table_name2.col
这也就是相等的时候才匹配
mysql> SELECT
-> fruits_name,language
-> FROM
-> fruits,culture
-> WHERE
-> fruits.fruits_origin = culture.location;
+-------------+----------+
| fruits_name | language |
+-------------+----------+
| 葡萄 | 山东话 |
| 苹果 | 山东话 |
| 香蕉 | 海南话 |
+-------------+----------+
3 rows in set (0.00 sec)
- 注意:最终的查询结果虽然减少了,但是匹配次数还是没有减少,匹配次数还是两张表的行数之积
给表起别名减少匹配次数
不是起了别名就可以减少次数了,起别名之后表名可以很简单,所有的字段都加上限制,包括SELECT后面的字段
起别名的方式和字段起别名的方式是相同的
mysql> SELECT
-> f.fruits_name '水果名称',l.language AS '地方方言'
-> FROM
-> fruits f,culture l
-> WHERE
-> f.fruits_origin = l.location;
+----------+----------+
| 水果名称 | 地方方言 |
+----------+----------+
| 葡萄 | 山东话 |
| 苹果 | 山东话 |
| 香蕉 | 海南话 |
+----------+----------+
3 rows in set (0.01 sec)
因为FROM是最先执行的,所以FROM之后起的别名后面都是可以用的,而这里SELECT是最后执行的,只是显示的时候才显示别名
这里给两张表都起了别名,并且就算不加别名,这里的f.fruits_name不会带入的,还是fruits_name
需要注意的是,这里是使用的SQL92语言
mysql> SELECT
-> f.fruits_name,c.language
-> FROM
-> fruits f,culture c
-> WHERE
-> f.fruits_origin = c.location;
+-------------+----------+
| fruits_name | language |
+-------------+----------+
| 葡萄 | 山东话 |
| 苹果 | 山东话 |
| 香蕉 | 海南话 |
+-------------+----------+
3 rows in set (0.04 sec)
字段的操作只会带入字段的操作过程,.引用并没有修改字段,不会带入字段名
通过笛卡尔积现象,表的连接次数越多效率越低,尽量避免表的连接次数,因为数据库的底层操作就是逐条匹配数据表的数据,匹配次数就是笛卡尔积,所以要对表使用别名来减少表的连接次数
内连接— 等值查询
内连接,就是INNER JOIN ON ,等值查询就是说表连接的条件是等量关系,比如这里就是f.fruits_origin = c.location时才查询
上面就是使用的是SQL92语法,这个语法的问题就在于结构不够清晰,因为表连接条件就是使用的WHERE来写的,但是查询的时候是需要进行其他过滤的,这样表的连接条件和普通的过滤条件就会使用AND连接在一起,结果不清晰
所以SQL99就改变了结构,特点就是连接条件是独立的,如果需要进一步的过滤,直接加WHERE再进行过滤
使用关键字JOIN 来表示两张表,ON来表达连接条件
所以上面的查询语句
mysql> SELECT
-> f.fruits_name,c.language
-> FROM
-> fruits f
-> JOIN //连接另外一张表
-> culture c
-> ON //连接条件
-> f.fruits_origin = c.location;
所以这个表连接过程和条件查询时分开的,就是讲两个过程分离,不能糅杂在一起
基本的格式就是
SELECT
……
FROM
table_name1
JOIN
table_name2 //需要连接table_name2表
ON
……连接条件
WHERE
……筛选条件
执行顺序就是进行FROM,之后执行JOIN语句,之后执行ON,连接条件,之后再执行WHERE……【之前的单表查询顺序】
这里其实就是内连接,省略了INNER,INNNER JOIN
mysql> SELECT
-> f.fruits_name,c.language
-> FROM
-> fruits f
-> INNER JOIN
-> culture c
-> ON
-> f.fruits_origin = c.location;
也就是默认情况下,就是内连接【带着INNER,可读性更好】
接下来的非等值连接还有内外连接的阐释明天继续,今天时间有点紧~🌳
|