MySQL數據庫3分組與單表、多表查詢

  • 2019 年 12 月 16 日
  • 筆記

浮華褪盡,人比煙花寂寞…… ——張愛玲

一、表操作的補充

select * from 表名 where 列名 in (值1,值2,。。。);

查出對應值的數據。

1.1null 和 not null

使用null的時候:

當創建的表中有null時我們如果需要查詢出來null所對應的信息,需要用select * from 表名 where 字段名 is null;

mysql> create table v1(id int auto_increment primary key,      -> name varchar(32),email varchar(32))charset=utf8;  Query OK, 0 rows affected (0.70 sec)    mysql> insert into v1(email) values('xxx');  Query OK, 1 row affected (0.07 sec)    mysql> select * from v1;  +----+------+-------+  | id | name | email |  +----+------+-------+  |  1 | NULL | xxx   |  +----+------+-------+  1 row in set (0.00 sec)    mysql> select * from v1 where name is null;  +----+------+-------+  | id | name | email |  +----+------+-------+  |  1 | NULL | xxx   |  +----+------+-------+  1 row in set (0.01 sec)    mysql> select *from v1 where name='';  Empty set (0.00 sec)

使用null會降低數據的查詢效率,不推薦使用,在創建表的時候建議把值默認為空。

1.2使用not null的時候

mysql> create table v2(id int auto_increment primary key,      -> name varchar(32) not null default '',email varchar(32)not null default '')charset=utf8;  Query OK, 0 rows affected (0.44 sec)      mysql> insert into v2(email) values('xxx');  Query OK, 1 row affected (0.06 sec)    mysql> select *from v2 where name='';  +----+------+-------+  | id | name | email |  +----+------+-------+  |  1 |      | xxx   |  +----+------+-------+  1 row in set (0.00 sec)

二、單表的操作(import)

2.1分組

分組:將所標記的某個相同字段進行歸類,比如員工信息表的職位分組,或者按照性別進行分組等。

2.1.1聚合函數

max(列)求出列中的最大值

min(列)求出列中的最小值

sum(列)對列中的數據求和

count(列)對列中的數據計數

avg(列)對列中的數據計算平均數

例子見group by

2.1.2group by

用法:

select 聚合函數, 選取的字段 from employee group by 分組的字段;

group by 是分組的關鍵詞,group by 必須和聚合函數(count)一塊出現。count(字段名),按照條件對字段中的數據進行計數。

例子:

1.以性別為例, 進行分組, 統計一下男生和女生的人數是多少個。

mysql> create table employee(      -> id int not null unique auto_increment primary key,      -> name varchar(20) not null,      -> gender enum('male','female') not null default 'male',      -> age int(3) unsigned not null default 28,      -> hire_date date not null,      -> post varchar(50),      -> post_comment varchar(100),      -> salary double(15,2),      -> office int,      -> depart_id int      -> )charset=utf8;  Query OK, 0 rows affected (0.61 sec)    mysql> insert into employee(name,gender,age,hire_date,post,salary,office,depart_id) values      -> ('小張','male',73,'20140701','研發部',3500,401,1),      -> ('小李','male',28,'20121101','研發部',2100,401,1),      -> ('小趙','female',18,'20150411','研發部',18000,403,3),      -> ('歪歪','female',48,'20150311','銷售部',3000.13,402,2),      -> ('丫丫','female',38,'20101101','銷售部',2000.35,402,2),      -> ('丁丁','female',18,'20110312','銷售部',1000.37,402,2),      -> ('小明','male',28,'20160311','運營部',10000.13,403,3),      -> ('小華','male',18,'19970312','運營部',20000,403,3),      -> ('小王','female',18,'20130311','運營部',19000,403,3);  Query OK, 9 rows affected (0.09 sec)  Records: 9  Duplicates: 0  Warnings: 0    mysql> select count(id),gender from employee group by gender;  +-----------+--------+  | count(id) | gender |  +-----------+--------+  |         4 | male   |  |         5 | female |  +-----------+--------+  2 rows in set (0.10 sec)    mysql> select gender,count(id) as total from employee group by gender;  #這裡可以用as重命名顯示的列名  +--------+-------+  | gender | total |  +--------+-------+  | male   |     4 |  | female |     5 |  +--------+-------+  2 rows in set (0.00 sec)

2.對部門進行分組, 求出每個部門年齡最大的那個人。

mysql> select depart_id , max(age) from employee group by depart_id;  +-----------+----------+  | depart_id | max(age) |  +-----------+----------+  |         1 |       73 |  |         2 |       48 |  |         3 |       28 |  +-----------+----------+  3 rows in set (0.04 sec)

3.對部門進行分組, 求出每個部門年齡求和。

mysql> select depart_id,sum(age) from employee group by depart_id;  +-----------+----------+  | depart_id | sum(age) |  +-----------+----------+  |         1 |      101 |  |         2 |      104 |  |         3 |       82 |  +-----------+----------+  3 rows in set (0.00 sec)

4.對部門進行分組, 求出每個部門年齡求平均數。

mysql> select depart_id,avg(age) from employee group by depart_id;  +-----------+----------+  | depart_id | avg(age) |  +-----------+----------+  |         1 |  50.5000 |  |         2 |  34.6667 |  |         3 |  20.5000 |  +-----------+----------+  3 rows in set (0.02 sec)

2.1.3having

對group by 之後的數據進行二次篩選

例子

5.對部門進行分組, 求出每個部門年齡求平均數,選出平均數最大的部門。

mysql> select depart_id,avg(age) from employee group by depart_id having avg(age)>35;  +-----------+----------+  | depart_id | avg(age) |  +-----------+----------+  |         1 |  50.5000 |  +-----------+----------+  1 row in set (0.00 sec)      mysql> select depart_id,avg(age)as pj from employee group by depart_id having pj>35;  +-----------+---------+  | depart_id | pj      |  +-----------+---------+  |         1 | 50.5000 |  +-----------+---------+  1 row in set (0.00 sec)

2.1.4升序和降序

order by 字段名 asc(升序)desc(降序)

升序和降序可以同時使用如age desc, id asc; 表示: 先對age進行降序, 如果age有相同的行, 則對id進行升序。

例子

mysql> select * from employee order by age desc,id desc;  +----+--------+--------+-----+------------+-----------+--------------+----------+--------+-----------+  | id | name   | gender | age | hire_date  | post      | post_comment | salary   | office | depart_id |  +----+--------+--------+-----+------------+-----------+--------------+----------+--------+-----------+  |  1 | 小張   | male   |  73 | 2014-07-01 | 研發部    | NULL         |  3500.00 |    401 |         1 |  |  4 | 歪歪   | female |  48 | 2015-03-11 | 銷售部    | NULL         |  3000.13 |    402 |         2 |  |  5 | 丫丫   | female |  38 | 2010-11-01 | 銷售部    | NULL         |  2000.35 |    402 |         2 |  |  7 | 小明   | male   |  28 | 2016-03-11 | 運營部    | NULL         | 10000.13 |    403 |         3 |  |  2 | 小李   | male   |  28 | 2012-11-01 | 研發部    | NULL         |  2100.00 |    401 |         1 |  |  9 | 小王   | female |  18 | 2013-03-11 | 運營部    | NULL         | 19000.00 |    403 |         3 |  |  8 | 小華   | male   |  18 | 1997-03-12 | 運營部    | NULL         | 20000.00 |    403 |         3 |  |  6 | 丁丁   | female |  18 | 2011-03-12 | 銷售部    | NULL         |  1000.37 |    402 |         2 |  |  3 | 小趙   | female |  18 | 2015-04-11 | 研發部    | NULL         | 18000.00 |    403 |         3 |  +----+--------+--------+-----+------------+-----------+--------------+----------+--------+-----------+  9 rows in set (0.00 sec)

2.1.5limit限制輸出

limit offset ,size

limit 起始行索引,向下查詢的長度(索引為0代表第一行)

例子

mysql> select * from employee limit 0,3;  +----+--------+--------+-----+------------+-----------+--------------+----------+--------+-----------+  | id | name   | gender | age | hire_date  | post      | post_comment | salary   | office | depart_id |  +----+--------+--------+-----+------------+-----------+--------------+----------+--------+-----------+  |  1 | 小張   | male   |  73 | 2014-07-01 | 研發部    | NULL         |  3500.00 |    401 |         1 |  |  2 | 小李   | male   |  28 | 2012-11-01 | 研發部    | NULL         |  2100.00 |    401 |         1 |  |  3 | 小趙   | female |  18 | 2015-04-11 | 研發部    | NULL         | 18000.00 |    403 |         3 |  +----+--------+--------+-----+------------+-----------+--------------+----------+--------+-----------+  3 rows in set (0.00 sec)

2.1.6查詢表示需要遵循的順序(important)

select * from 表名 where 條件 group by 條件 having 條件 order by 條件 limit 條件;

where > group by > having > order by > limit

三、多表操作

外鍵

主關鍵字(primary key)是表中的一個或多個字段,它的值用於唯一地標識表中的某一條記錄。

公共關鍵字(Common Key)在關係數據庫中,關係之間的聯繫是通過相容或相同的屬性或屬性組來表示的。如果兩個關係中具有相容或相同的屬性或屬性組,那麼這個屬性或屬性組被稱為這兩個關係的公共關鍵字。

如果公共關鍵字在一個關係中是主關鍵字,那麼這個公共關鍵字被稱為另一個關係的外鍵。由此可見,外鍵表示了兩個關係之間的相關聯繫。以另一個關係的外鍵作主關鍵字的表被稱為主表,具有此外鍵的表被稱為主表的從表。外鍵又稱作外關鍵字

使用外鍵的原因:

1.減少佔用的內存空間

2.只需要修改主表的數據,從表的數據也會相應的跟着修改

3.1一對多

一對多指一個主表中的數據和從表中的數據是一對多的關係,如下例,一個部門可以有多個員工。

使用方法:

constraint 外鍵名 foreign key (被約束的字段) references 約束的表(約束的字段)

mysql> create table department(      -> id int auto_increment primary key,      -> name varchar(32) not null default '')      -> charset utf8;  Query OK, 0 rows affected (0.42 sec)    mysql> insert into department(name) values('研發部'),('運維部'),('前台部'),('小賣部');  Query OK, 4 rows affected (0.06 sec)  Records: 4  Duplicates: 0  Warnings: 0    mysql> create table userinfo(id int auto_increment primary key,      -> name varchar(32) not null default '',      -> depart_id int not null default 1,      -> constraint fk_user_depart foreign key (depart_id) references department(id))      -> charset utf8;  Query OK, 0 rows affected (0.39 sec)    mysql> insert into userinfo (name,depart_id) values('xiaozhu',1),('xiaoyu',1),      -> ('laohe',2),('longge',2),('ludi',3),('xiaoguo',4);  Query OK, 6 rows affected (0.21 sec)  Records: 6  Duplicates: 0  Warnings: 0    mysql> select * from userinfo;  +----+---------+-----------+  | id | name    | depart_id |  +----+---------+-----------+  |  1 | xiaozhu |         1 |  |  2 | xiaoyu  |         1 |  |  3 | laohe   |         2 |  |  4 | longge  |         2 |  |  5 | ludi    |         3 |  |  6 | xiaoguo |         4 |  +----+---------+-----------+  6 rows in set (0.00 sec)    mysql> select * from department;  +----+-----------+  | id | name      |  +----+-----------+  |  1 | 研發部    |  |  2 | 運維部    |  |  3 | 前台部    |  |  4 | 小賣部    |  +----+-----------+  4 rows in set (0.00 sec)    mysql> insert into userinfo(name,depart_id) values('xiaozhang',5);#depart_id受department.id的約束  ERROR 1452 (23000): Cannot add or update a child row: a foreign key constraint fails (`test2`.`userinfo`, CONSTRAINT `fk_user_depart` FOREIGN KEY (`depart_id`) REFERENCES `department` (`id`))    #聯表查詢  mysql> select userinfo.name as uname,department.name as dname from userinfo left      -> join department on depart_id = department.id;  +---------+-----------+  | uname   | dname     |  +---------+-----------+  | xiaozhu | 研發部    |  | xiaoyu  | 研發部    |  | laohe   | 運維部    |  | longge  | 運維部    |  | ludi    | 前台部    |  | xiaoguo | 小賣部    |  +---------+-----------+  6 rows in set (0.00 sec)

3.2多對多

多對多指當一個主表有多個從表時,從表之間的每個數據之間的關係就是多對多,如下圖,一個boy可以和多個girl約會,一個girl也可以和多個boy約會。

mysql> create table boy(id int auto_increment primary key,      -> bname varchar(32) not null default'')charset utf8;  Query OK, 0 rows affected (0.36 sec)    mysql> insert into boy(bname) values('zhangsan'),('lisi'),('wangwu');  Query OK, 3 rows affected (0.09 sec)  Records: 3  Duplicates: 0  Warnings: 0    mysql> create table girl(id int auto_increment primary key,      -> gname varchar(32) not null default'')charset utf8;  Query OK, 0 rows affected (0.33 sec)    mysql> insert into girl(gname) values('xiaoli'),('xiaohua'),('xiaomei');  Query OK, 3 rows affected (0.06 sec)  Records: 3  Duplicates: 0  Warnings: 0    mysql> create table boy_girl(id int auto_increment primary key,      -> bid int not null default 1,      -> gid int not null default 1,      -> constraint fk_boy_girl_boy foreign key(bid) references boy(id),      -> constraint fk_boy_girl_girl foreign key(gid) references girl(id)      -> )charset utf8;  Query OK, 0 rows affected (0.42 sec)    mysql> insert into boy_girl(bid,gid) values(1,1),(2,2),(3,3),(3,1),(2,1),(1,2);  Query OK, 6 rows affected (0.04 sec)  Records: 6  Duplicates: 0  Warnings: 0    mysql> select * from boy left join boy_girl on boy.id = boy_girl.bid left join girl      -> on girl.id = boy_girl.gid;  +----+----------+------+------+------+------+---------+  | id | bname    | id   | bid  | gid  | id   | gname   |  +----+----------+------+------+------+------+---------+  |  1 | zhangsan |    1 |    1 |    1 |    1 | xiaoli  |  |  2 | lisi     |    5 |    2 |    1 |    1 | xiaoli  |  |  3 | wangwu   |    4 |    3 |    1 |    1 | xiaoli  |  |  1 | zhangsan |    6 |    1 |    2 |    2 | xiaohua |  |  2 | lisi     |    2 |    2 |    2 |    2 | xiaohua |  |  3 | wangwu   |    3 |    3 |    3 |    3 | xiaomei |  +----+----------+------+------+------+------+---------+  6 rows in set (0.03 sec)    mysql> select bname,gname from boy left join boy_girl on boy.id = boy_girl.bid      -> left join girl on girl.id = boy_girl.gid;  +----------+---------+  | bname    | gname   |  +----------+---------+  | zhangsan | xiaoli  |  | lisi     | xiaoli  |  | wangwu   | xiaoli  |  | zhangsan | xiaohua |  | lisi     | xiaohua |  | wangwu   | xiaomei |  +----------+---------+  6 rows in set (0.00 sec)

3.3一對一

一對一指的是兩個表中的數據是一對一的關係,使用unique(字段名)來約束這種關係。如下例,由於工資屬於員工的敏感信息,用單獨的表去存儲,這時工資和員工信息就是一對一的關係。

mysql> create table priv(      -> id int auto_increment primary key,      -> salary int not null default 0,      -> uid int not null default 1,      -> constraint fk_priv_user foreign key (uid) references userinfo(id),      -> unique(uid)) charset=utf8;  Query OK, 0 rows affected (0.52 sec)    mysql> insert into priv(salary,uid) values (10000,1),(12000,2),(15000,3),(8000,4),(9000,5),(9900,6);  Query OK, 6 rows affected (0.16 sec)  Records: 6  Duplicates: 0  Warnings: 0    mysql> select name,salary from userinfo left join priv on priv.uid = userinfo.id;  +---------+--------+  | name    | salary |  +---------+--------+  | xiaozhu |  10000 |  | xiaoyu  |  12000 |  | laohe   |  15000 |  | longge  |   8000 |  | ludi    |   9000 |  | xiaoguo |   9900 |  +---------+--------+  6 rows in set (0.00 sec)

3.4多表聯查

多表聯查就是將多個有關係的表放在一起查,使用的語句有:

left join……on查詢時以左邊的數據為主

right join ……on查詢時以右邊的數據為主

mysql> insert into department(name) values('業務部');  Query OK, 1 row affected (0.12 sec)    mysql> select userinfo.name as uname,department.name as dname from userinfo left      -> join department on depart_id = department.id;  +---------+-----------+  | uname   | dname     |  +---------+-----------+  | xiaozhu | 研發部    |  | xiaoyu  | 研發部    |  | laohe   | 運維部    |  | longge  | 運維部    |  | ludi    | 前台部    |  | xiaoguo | 小賣部    |  +---------+-----------+  6 rows in set (0.00 sec)    mysql> select userinfo.name as uname,department.name as dname from userinfo right      -> join department on depart_id = department.id;  +---------+-----------+  | uname   | dname     |  +---------+-----------+  | xiaozhu | 研發部    |  | xiaoyu  | 研發部    |  | laohe   | 運維部    |  | longge  | 運維部    |  | ludi    | 前台部    |  | xiaoguo | 小賣部    |  | NULL    | 業務部    |  +---------+-----------+  7 rows in set (0.00 sec)