多表關係和查詢

多表關係

社會中存儲須要能夠構建成表的數據, 它們造成的表,每每之間存儲某種或某些社會關係,python

mysql數據庫創建表結構就是社會中產生的各類數據, 分門別類管理mysql

但mysql創建的(代碼層次的)表之間, 一樣須要處理表與表之間的關係linux

造成了 多對一 | 多對多 | 一對一 三種關係程序員

"""
一對一:丈夫-妻子,用戶-身份證,做者-做者詳情
一對多:部門-員工,班級-學生,書-出版社
多對多:老師-班級,課程-學生,出版社-做者
"""

# 書 - 出版社 - 做者 - 做者詳情 外鍵分佈
# 外鍵是 創建表與表關聯 的字段,一般 一個表的外鍵 是 另外一個表的主鍵(惟一鍵也能夠)

# 一對一:外鍵在任何一方均可以,此時外鍵要設置 惟一鍵
"""
做者(author):id,name,sex,age,mobile
做者詳情(author_detail): id,info,address,author_id
----------------------------------------------------
做者(author):id,name,sex,age,mobile, detail_id
1 Tom 1
2 Bom 2
3 Bob 3

做者詳情(author_detail): id,info,address
1 Tom_info
2 Bom_info
"""

# 一對多:外鍵必須放在多的一方,此時外鍵值不惟一
"""
書(book):id,name,price,publish_id
1 西遊記 1
2 東遊記 2
3 西廂記 1
4 流浪記 1

出版社(publish): id,name,address,phone
1 老奶奶出版社
2 小奶奶出版社
"""

# 多對多:必定要建立第三張表(關係表),每個外鍵值不惟一,看能夠多個外鍵創建聯合惟一
"""
做者(author):id, name, age
出版社(publish):id, name, address
做者與出版社關係表:
id      author_id       publish_id
1           1               1
2           1               2
3           2               1
4           2               2
"""

約束條件中的外鍵

重點:外鍵字段自己能夠惟一或不惟一,可是外鍵關聯的字段必定惟一
# 做者(author):id,name,sex,age,mobile, detail_id
# 做者詳情(author_detail): id,info,address

# 一、外鍵的 字段名 能夠自定義(名字隨意),一般命名規範(關聯表_關聯字段)

# 二、外鍵要經過 foreign key 語法創建表與表之間的關聯

# 三、foreign key(所在表的外鍵字段) references 關聯表(關聯字段)
# eg>:foreign key(detail_id) references author_detail(id)

# 四、級聯關係
#   級聯更新 on update cascade
#   級聯刪除 on delete cascade

一對一:無級聯關係

# 做者詳情(author_detail): id,info,address
create table author_detail(
    id int primary key auto_increment,
    info varchar(256),
    address varchar(256)
);


# 做者表id,name,sex,age,mobile, detail_id
create table author(
    id int primary key auto_increment,
    name varchar(64) not null,
    mobile char(11) unique not null,
    sex enum('男', '女') default '男',
    age int default 0,
    detail_id int unique not null,
    foreign key(detail_id) references author_detail(id)
);

# 必須先建立被關聯表數據,有關聯表外鍵關聯的記錄後,關聯表才能夠建立數據
mysql>: insert into author_detail(info,address) values('Tom_info','Tom_address');
mysql>: insert into author(name,mobile,detail_id) values('Tom','13344556677', 1);
mysql>: insert into author_detail(info,address) values('Bob_info','Bob_address');
mysql>: insert into author(name,mobile,detail_id) values('Bob','15666882233', 2);
###############################################################################
mysql> select * from author_detail;
+----+----------+-------------+
| id | info     | address     |
+----+----------+-------------+
|  1 | TOM_info | TOM_address |
|  2 | Bob_info | Bob_address |
+----+----------+-------------+
2 rows in set (0.00 sec)

mysql> select * from author;
+----+------+-------------+------+------+-----------+
| id | name | mobile      | sex  | age  | detail_id |
+----+------+-------------+------+------+-----------+
|  1 | Tom  | 13344556677 | 男   |    0 |         1 |
|  2 | Bob  | 15666882233 | 男   |    0 |         2 |
+----+------+-------------+------+------+-----------+
2 rows in set (0.00 sec)
###############################################################################
# 修改關聯表 author
mysql>: insert into author_detail(info,address) values('Tom_info_sup','Tom_address_sup');
mysql>: update author set detail_id=3 where detail_id=2; # 有未被其餘數據關聯的數據,就能夠修改
# 刪除關聯表 author
mysql>: delete from author where detail_id=3;  # 直接刪除

# 修改被關聯表 author_detail
mysql>: update author_detail set id=10 where id=1;  # 沒法修改
# 刪除被關聯表 author_detail
mysql>: delete from author_detail where id=1;  # 沒法刪除

# 沒有級聯關係下:
# 增長:先增長被關聯表記錄,再增長關聯表記錄
# 刪除:先刪除關聯表記錄,再刪除被關聯表記錄
# 更新:關聯與被關聯表都沒法完成 關聯的外鍵和主鍵 數據更新 - (若是被關聯表記錄沒有被綁定,能夠修改)

一對一:有級聯關係

建表規則:
未存放外鍵的表被依賴,稱之爲左表(被關聯表);存放外鍵的表示依賴表,稱之爲右表(關聯表);先操做被關聯表再操做關聯表
mysql>: drop table author;
mysql>: drop table author_detail;


# 做者詳情(author_detail): id,info,address
create table author_detail(
    id int primary key auto_increment,
    info varchar(256),
    address varchar(256)
);

# 做者表id,name,sex,age,mobile, detail_id
create table author(
    id int primary key auto_increment,
    name varchar(64) not null,
    mobile char(11) unique not null,
    sex enum('男', '女') default '男',
    age int default 0,
    detail_id int unique not null,
    foreign key(detail_id) references author_detail(id)
    on update cascade 
    on delete cascade
);



# 必須先建立被關聯表數據,有關聯表外鍵關聯的記錄後,關聯表才能夠建立數據
mysql>: insert into author(name,mobile,detail_id) values('Tom','13344556677', 1);  # 錯誤
mysql>: insert into author_detail(info,address) values('Tom_info','Tom_address');
mysql>: insert into author(name,mobile,detail_id) values('Tom','13344556677', 1);
mysql>: insert into author_detail(info,address) values('Bob_info','Bob_address');
mysql>: insert into author(name,mobile,detail_id) values('Bob','15666882233', 2);

# 修改關聯表 author
mysql>: update author set detail_id=3 where detail_id=2;  # 失敗,3詳情不存在
mysql>: update author set detail_id=1 where detail_id=2;  # 失敗,1詳情已被關聯
mysql>: insert into author_detail(info,address) values('Tom_info_sup','Tom_address_sup');
mysql>: update author set detail_id=3 where detail_id=2; # 有未被其餘數據關聯的數據,就能夠修改
# 刪除關聯表 author
mysql>: delete from author where detail_id=3;  # 直接刪除

# 修改被關聯表 author_detail
mysql>: update author_detail set id=10 where id=1;  # 級聯修改,同步關係關聯表外鍵

# 刪除被關聯表 author_detail
mysql>: delete from author where detail_id=10;  # 能夠刪除對被關聯表無影響
mysql>: insert into author(name,mobile,detail_id) values('Tom','13344556677', 10);
mysql>: delete from author_detail where id=10;  # 能夠刪除,將關聯表的記錄級聯刪除掉

一對多

# 一對多:外鍵必須放在多的一方,此時外鍵值不惟一

# 出版社(publish): id,name,address,phone
create table publish(
    id int primary key auto_increment,
    name varchar(64),
    address varchar(256),
    phone char(20)
);

# 書(book):id,name,price,publish_id, author_id
create table book(
    id int primary key auto_increment,
    name varchar(64) not null,
    price decimal(5, 2) default 0,
    publish_id int,  # 一對多的外鍵不能設置惟一
    foreign key(publish_id) references publish(id)
    on update cascade
    on delete cascade
);

# 增:先增長被關聯表(publish)的數據,再增長關聯表(book)的數據
mysql>: insert into publish(name, address, phone) values
('人民出版社', '北京', '010-110'),
('西交大出版社', '西安', '010-119'),
('老男孩出版社', '上海', '010-120');

mysql>: insert into book(name, price, publish_id) values
('西遊記', 6.66, 1),
('東遊記', 8.66, 1),
('python從入門到入土', 2.66, 2),
('輪程序員修養之道', 3.66, 3),
('好好活着', 88.88, 3);
# 沒有被關聯的字段,插入依舊錯誤
mysql>: insert into book(name, price, publish_id) values ('打臉之道', 0.3, 4);  # 失敗


# 更新:直接更新被關聯表的(publish) 主鍵,關聯表(book) 外鍵 會級聯更新
mysql>: update publish set id=10 where id=1;
# 更新:直接更新關聯表的(book) 外鍵,修改的值對應被關聯表(publish) 主鍵 若是存在,能夠更新成功,反之失敗
mysql>: update book set publish_id=2 where id=4;  # 成功
mysql>: update book set publish_id=1 where id=4;  # 失敗


# 刪:
#   刪被關聯表,關聯表會被級聯刪除
mysql>: delete from publish where id = 2;

#   刪關聯表,被關聯表不會發生變化
mysql>: delete from book where publish_id = 3;
# 假設:書與做者也是 一對多 關係,一個做者能夠出版多本書
create table book(
    id int primary key auto_increment,
    name varchar(64) not null,
    price decimal(5, 2) default 0,
    publish_id int,  # 一對多的外鍵不能設置惟一
    foreign key(publish_id) references publish(id)
    on update cascade
    on delete cascade
    
    # 創建與做者 一對多 的外鍵關聯
    author_id int,  
    foreign key(author_id) references author(id)
    on update cascade
    on delete cascade
);

多對多

# 多對多:必定要建立第三張表(關係表),每個外鍵值不惟一,看能夠多個外鍵創建聯合惟一

mysql>: drop table author;
mysql>: drop table author_detail;
mysql>: drop table book;
mysql>: drop table publish;

# 做者(author):id, name, age
create table author(
    id int primary key auto_increment,
    name varchar(64),
    age int unsigned default 0
);

# 出版社(publish):id, name, address
create table publish(
    id int primary key auto_increment,
    name varchar(64),
    address varchar(256)
);

# 做者與出版社關係表:id, author_id, publish_id
create table author_publish(
    id int primary key auto_increment,
    # 關係表必定有多個外鍵,關聯着多張表
    # 關聯做者表
    author_id int,
    foreign key(author_id) references author(id)
    on update cascade
    on delete cascade,
    # 關聯出版社表
    publish_id int,
    foreign key(publish_id) references publish(id)
    on update cascade
    on delete cascade,
    # 創建兩個字段的聯合惟一
    unique(author_id, publish_id)
);

# 注:關係表 關聯着 做者 和 出版社 兩張表,在表結構上 做者 與 出版社 兩表鍵沒有任何關係


# 增:兩張被關聯表,沒有先後關係,但關係表必須在兩個表都提供數據後才能進行 關係匹配
mysql>: insert into author(name, age) values('ruakei', 67),('engo', 76),('Lxx', 3);
mysql>: insert into publish(name, address) values('老男孩出版社', '上海'),('小女孩出版社', '北京');

# 操做關係表:
mysql>: insert into author_publish(author_id, publish_id) values(1,1),(1,2),(2,1),(2,2),(3,1);

# 關係表操做:增、刪、改,只要兩張被關係表有提供對應的操做數據,均可以操做成功,且對兩張被關係表沒有影響


# 操做兩張被關係表:
#       增:不會影響關係表
mysql>: insert into publish(name, address) values('西交大出版社', '西安');
#       改:關係表都會級聯更新
mysql>: update publish set id=10 where id=1;
#       刪:關係表都會級聯刪除
mysql>: delete from author where name='ruakei';

多表關係小練習

一、建立一個stu表,字段有:自增主鍵id,不爲空姓名,默認值性別(枚舉類型),無限制身高
create table stu(
    id int primary key auto_increment,
    name varchar(256) not null,
    gender enum('男','女') default '男',
    height float(5,2) unsigned
);
二、爲stu表依次插入如下三條數據

​   i)插入一條包含id,name,gender,height四個信息的數據
insert into stu values(1,'tom','男',180.88);

​   ii)插入一條name,gender,height三個信息的數據
insert into stu(name,gender,height) values('bob','女',155.55);
​   iii)插入一條只有name信息的數據
insert into stu(name) values('rock');

mysql> select * from stu;
+----+------+--------+--------+
| id | name | gender | height |
+----+------+--------+--------+
|  1 | tom  | 男     | 180.88 |
|  2 | bob  | 女     | 155.55 |
|  3 | rock | 男     |   NULL |
+----+------+--------+--------+

三、建立一張有姓名、年齡的teacher表,在最後添加工資字段,在姓名後添加id主鍵字段
mysql> create table teacher(
    name varchar(256),
    id int primary key auto_increment,
    age int,
    sarlay float(5,2)
);
mysql> desc teacher;
+--------+--------------+------+-----+---------+----------------+
| Field  | Type         | Null | Key | Default | Extra          |
+--------+--------------+------+-----+---------+----------------+
| name   | varchar(256) | YES  |     | NULL    |                |
| id     | int(11)      | NO   | PRI | NULL    | auto_increment |
| age    | int(11)      | YES  |     | NULL    |                |
| sarlay | float(5,2)   | YES  |     | NULL    |                |
+--------+--------------+------+-----+---------+----------------+

四、思考:將4中id字段移到到表的最前方,造成最終字段順序爲id、姓名、年齡、工資
mysql> alter table teacher modify id int first;
mysql> desc teacher;
+--------+--------------+------+-----+---------+-------+
| Field  | Type         | Null | Key | Default | Extra |
+--------+--------------+------+-----+---------+-------+
| id     | int(11)      | NO   | PRI | 0       |       |
| name   | varchar(256) | YES  |     | NULL    |       |
| age    | int(11)      | YES  |     | NULL    |       |
| sarlay | float(5,2)   | YES  |     | NULL    |       |
+--------+--------------+------+-----+---------+-------+
五、完成 學生表 與 國家表 的 多對一 表關係的建立,並完成數據測試
mysql> create table country(
         id int primary key auto_increment,
         name char(16)
     );

mysql> create table student(
         id int primary key auto_increment,
         name varchar(256) not null,
         gender enum('男','女') default '男',
         country_id int,
         foreign key(country_id) references country(id)
         on update cascade
         on delete cascade
     );

#增長數據
mysql> insert into country(name) values('中國');
mysql> insert into student(name,gender,country_id) values('Bob','男',1),('Tom','男',1),('Cob','男',1),('Tob','女',1);



# 更新數據

# 能夠對被關聯表進行更改


mysql> update country set id=10 where id=1;

mysql> update student set id=1 where id=10;


# 不能對外鍵直接更改
#錯誤
mysql> update student set country_id=1 where country_id=10;
ERROR 1452 (23000): Cannot add or update a child row: a foreign key constraint fails (`db2`.`student`, CONSTRAINT `student_ibfk_1` FOREIGN KEY (`country_id`) REFERENCES `country` (`id`) ON DELETE CASCADE ON UPDATE CASCADE)



#刪除數據

mysql> delete from student where id=1;

mysql> select * from student;
+----+------+--------+------------+
| id | name | gender | country_id |
+----+------+--------+------------+
|  2 | Tom  | 男     |         10 |
|  3 | Cob  | 男     |         10 |
|  4 | Tob  | 女     |         10 |
+----+------+--------+------------+

mysql> select * from country;
+----+--------+
| id | name   |
+----+--------+
| 10 | 中國   |
+----+--------+

mysql> delete from country where id=10;

mysql> select * from student;
Empty set (0.00 sec)

mysql> select * from country;
Empty set (0.00 sec)

六、完成 學生表 與 課程表 的 多對多 表關係的建立,並完成數據測試
 create table student(
         id int primary key auto_increment,
         name varchar(256) not null,
         gender enum('男','女') default '男'
     );
create table course(
    id int primary key auto_increment,
    name char(16)
);
create table student_course(
    id int primary key auto_increment,
    student_id int not null,
    foreign key(student_id) references student(id)
    on update cascade
    on delete cascade,
    course_id int not null,
    foreign key(course_id) references course(id)
    on update cascade
    on delete cascade
);





# 增長數據

mysql> insert into student(name,gender) values('Bob','男'),('Tom','男'),('Cob','男'),('Tob','女');

mysql> insert into course(name) values('數學'),('python'),('linux');

mysql> insert into student_course(student_id,course_id) values(1,1),(1,2),(1,3),(2,2),(2,3),(3,3);


# 增長
mysql> insert into student(name,gender) values('Aob','男');

#改

mysql> update student set id=10 where id=1;

mysql> update course set id=20 where id=1;



#刪

mysql> delete from student where id=10;


mysql> select * from student_course;
+----+------------+-----------+
| id | student_id | course_id |
+----+------------+-----------+
|  4 |          2 |         2 |
|  5 |          2 |         3 |
|  6 |          3 |         3 |
+----+------------+-----------+

mysql> select * from student;
+----+------+--------+
| id | name | gender |
+----+------+--------+
|  2 | Tom  | 男     |
|  3 | Cob  | 男     |
|  4 | Tob  | 女     |
|  5 | Aob  | 男     |
+----+------+--------+

mysql> select * from course;
+----+--------+
| id | name   |
+----+--------+
|  2 | python |
|  3 | linux  |
| 20 | 數學   |
+----+--------+

七、完成 學生表 與 學生簡介表 的 一對一 表關係的建立,並完成數據測試
create table student_info(
    id int primary key auto_increment,
    info varchar(256),
    address varchar(256)
);
create table student(
    id int primary key auto_increment,
    name varchar(256) not null,
    gender enum('男','女') default '男',
    info_id int not null,
    foreign key(info_id) references student_info(id)
    on update cascade
    on delete cascade
 );
 #建立後




################增長數據
mysql> insert into student_info(info,address) values('BOb_info','Bob_address'),('Tom_info','Tom_address');

mysql> insert into student(name,gender,info_id) values('Bob','男',1),('Tom','男',2);


### 修改數據
mysql> update student set id=10 where id=1;
mysql> update student_info set id=10 where id=1;
mysql> select * from student;
+----+------+--------+---------+
| id | name | gender | info_id |
+----+------+--------+---------+
|  2 | Tom  | 男     |       2 |
| 10 | Bob  | 男     |      10 |
+----+------+--------+---------+

八、將 學生表、國家表、課程表、學生簡介表 四個表放在一塊兒考慮表關係,並完成數據的增刪測試
 #國家表
 create table country(
     id int primary key auto_increment,
     name char(16)
 );
 
#學生簡介
create table student_info(
    id int primary key auto_increment,
    info varchar(256),
    address varchar(256)
);

#學生表
create table student(
    id int primary key auto_increment,
    name varchar(256) not null,
    gender enum('男','女') default '男',
    info_id int not null,
    foreign key(info_id) references student_info(id)
    on update cascade
    on delete cascade,
    country_id int not null,
    foreign key(country_id) references country(id)
    on update cascade
    on delete cascade   
 ); 
 
 
#課程表 
 create table course(
    id int primary key auto_increment,
    name char(16)
);

#多對多學生和課程
create table student_course(
    id int primary key auto_increment,
    student_id int not null,
    foreign key(student_id) references student(id)
    on update cascade
    on delete cascade,
    course_id int not null,
    foreign key(course_id) references course(id)
    on update cascade
    on delete cascade
);


#增長

mysql> insert into country(name) values('中國');

mysql> insert into student_info(info,address) values('BOb_info','Bob_address'),('Tom_info','Tom_address');

mysql> insert into student(name,gender,info_id,country_id) values('Bob','男',1,1),('Tom','男',1,1);

mysql> insert into course(name) values('數學'),('python'),('linux');

mysql> insert into student_course(student_id,course_id) values(1,1),(1,2),(1,3),(2,2),(2,3);


#刪除
mysql> delete from course where id=1;

mysql> delete from student where id=1;

mysql> select * from student;
+----+------+--------+---------+------------+
| id | name | gender | info_id | country_id |
+----+------+--------+---------+------------+
|  2 | Tom  | 男     |       1 |          1 |
+----+------+--------+---------+------------+


mysql> select * from student_info;
+----+----------+-------------+
| id | info     | address     |
+----+----------+-------------+
|  1 | BOb_info | Bob_address |
|  2 | Tom_info | Tom_address |
+----+----------+-------------+

mysql> select * from course;
+----+--------+
| id | name   |
+----+--------+
|  2 | python |
|  3 | linux  |
+----+--------+

mysql> select * from student_course;
+----+------------+-----------+
| id | student_id | course_id |
+----+------------+-----------+
|  4 |          2 |         2 |
|  5 |          2 |         3 |
+----+------------+-----------+

查詢

查詢語法

select [distinct] 字段1 [[as] 別名], ..., 字段n [[as] 別名] from [庫名.]表名
                    [
                    where 約束條件
                    group by 分組依據
                    having 過濾條件
                    order by 排序的字段
                    limit 限制顯示的條數
                    ];
注:
1.查表中全部字段用*表示
2.條件的書寫規則嚴格按照語法順序書寫,能夠缺省,但不能夠錯序
3.約束條件的流程:from -> where -> group by -> having -> distinct -> order by -> limit
4.字段能夠起別名
5.字段能夠直接作運算 select age + 1 'new_age' from emp;
6.分組後的條件都可以使用聚合函數

                        
3.
def from():
    return "查詢的文件"
def where(file):
    return "條件篩選後的結果"
def group_by(res):
    return "分組後的結果"
def having(res):
    return "再次過濾後的結果"
def distinct(res):
    return "去重後的結果"
def order_by(res):
    return "排序後的結果"
def limit(res):
    return "限制條數後的結果"

def select(from=from, where=null, ..., limit=null):
    file = from()
    res = where(file) if where else file
    res = group_by(res) if group_by else res
    ...
    res = limit(res) if limit else res
    
    return res
select(where=where, group_by=group_by)

單表查詢

sql中幾乎全部的操做都是單表查詢,多表也會連成單邊,臨時表也會建立視圖。正則表達式

select distinct 字段 from 表 where group by having order by limitsql

"""
增:
insert [into] 
    [數據庫名.]表名[(字段1[, ..., 字段n])] 
values 
    (數據1[, ..., 數據n])[, ..., (數據1[, ..., 數據n])];

刪:
delete from [數據庫名.]表名 [條件];

改:
updata [數據庫名.]表名 set 字段1=值1[, ..., 字段n=值n] [條件];

查:
select [distinct] 字段1 [[as] 別名1],...,字段n [[as] 別名n] from [數據庫名.]表名 [條件];
"""

# 條件:from、where、group by、having、distinct、order by、limit => 層層篩選後的結果
# 注:一條查詢語句,能夠擁有多種篩選條件,條件的順序必須按照上方順序進行逐步篩選,distinct稍有特殊(書寫位置),條件的種類能夠不全
# 能夠缺失,但不能亂序

去重:distinct

mysql>: 
create table t1(
    id int,
    x int,
    y int
);

mysql>: insert into t1 values(1, 1, 1), (2, 1, 2), (3, 2, 2), (4, 2, 2);

mysql>: select distinct * from t1;  # 所有數據

mysql>: select distinct x, y from t1;  # 結果 1,1  1,2  2,2

mysql>: select distinct y from t1;  # 結果 1  2

# 總結:distinct對參與查詢的全部字段,總體去重(所查的所有字段的值都相同,才認爲是重複數據)

數據準備

CREATE TABLE `emp`  ( 
  `id` int(0) NOT NULL AUTO_INCREMENT,
  `name` varchar(10) NOT NULL,
  `gender` enum('男','女','未知') NULL DEFAULT '未知',
  `age` int(0) NULL DEFAULT 0,
  `salary` float NULL DEFAULT 0,
  `area` varchar(20) NULL DEFAULT '中國',
  `port` varchar(20) DEFAULT '未知',
  `dep` varchar(20),
  PRIMARY KEY (`id`)
);

INSERT INTO `emp` VALUES 
    (1, 'yangsir', '男', 42, 10.5, '上海', '浦東', '教職部'),
    (2, 'engo', '男', 38, 9.4, '山東', '濟南', '教學部'),
    (3, 'jerry', '女', 30, 3.0, '江蘇', '張家港', '教學部'),
    (4, 'tank', '女', 28, 2.4, '廣州', '廣東', '教學部'),
    (5, 'jiboy', '男', 28, 2.4, '江蘇', '蘇州', '教學部'),
    (6, 'zero', '男', 18, 8.8, '中國', '黃浦', '諮詢部'),
    (7, 'owen', '男', 18, 8.8, '安徽', '宣城', '教學部'),
    (8, 'jason', '男', 28, 9.8, '安徽', '巢湖', '教學部'),
    (9, 'ying', '女', 36, 1.2, '安徽', '蕪湖', '諮詢部'),
    (10, 'kevin', '男', 36, 5.8, '山東', '濟南', '教學部'),
    (11, 'monkey', '女', 28, 1.2, '山東', '青島', '教職部'),
    (12, 'san', '男', 30, 9.0, '上海', '浦東', '諮詢部'),
    (13, 'san1', '男', 30, 6.0, '上海', '浦東', '諮詢部'),
    (14, 'san2', '男', 30, 6.0, '上海', '浦西', '教學部'),
    (15, 'ruakei', '女', 67, 2.501, '上海', '陸家嘴', '教學部');

經常使用函數

拼接:
    concat(字段1,...,字段n):完成字段的拼接
    concat_ws(x, 字段1,...,字段n):完成字段的拼接,x爲鏈接符


大小寫:
    lower():小寫
    upper():大寫
浮點型操做:
    ceil():向上取整
    floor():向下取整
    round():四捨五入
整型:能夠直接運算



mysql>: select name,area,port from emp;

mysql> select name,area,port from emp limit 3;
+---------+--------+-----------+
| name    | area   | port      |
+---------+--------+-----------+
| yangsir | 上海   | 浦東      |
| engo    | 山東   | 濟南      |
| jerry   | 江蘇   | 張家港    |
+---------+--------+-----------+

mysql>: select name as 姓名, concat(area,'-',port) 地址 from emp;  # 上海-浦東

mysql> select name as 姓名,concat(area,'-',port) 地址 from emp limit 3;
+---------+------------------+
| 姓名    | 地址             |
+---------+------------------+
| yangsir | 上海-浦東        |
| engo    | 山東-濟南        |
| jerry   | 江蘇-張家港      |
+---------+------------------+

mysql>: select name as 姓名, concat_ws('-',area,port,dep) 信息 from emp;  # 上海-浦東-教職部

mysql> select name as 姓名,concat_ws('-',area,port,dep) 地址 from emp limit 3;
+---------+----------------------------+
| 姓名    | 地址                       |
+---------+----------------------------+
| yangsir | 上海-浦東-教職部           |
| engo    | 山東-濟南-教學部           |
| jerry   | 江蘇-張家港-教學部         |
+---------+----------------------------+
3 rows in set (0.03 sec)
mysql>: select upper(name) 姓名大寫,lower(name) 姓名小寫 from emp;

mysql> select upper(name) 大寫姓名,lower(name) 小寫姓名 from emp limit 3;
+--------------+--------------+
| 大寫姓名     | 小寫姓名     |
+--------------+--------------+
| YANGSIR      | yangsir      |
| ENGO         | engo         |
| JERRY        | jerry        |
+--------------+--------------+

mysql>: select id,salary,ceil(salary)上薪資,floor(salary)下薪資,round(salary)入薪資 from emp;

mysql> select salary,ceil(salary) 上薪資,floor(salary) 下薪資,round(salary) 四捨五入薪資 from emp limit 3;
+--------+-----------+-----------+--------------------+
| salary | 上薪資    | 下薪資    | 四捨五入薪資       |
+--------+-----------+-----------+--------------------+
|   10.5 |        11 |        10 |                 10 |
|    9.4 |        10 |         9 |                  9 |
|      3 |         3 |         3 |                  3 |
+--------+-----------+-----------+--------------------+

mysql>: select name 姓名, age 舊年齡, age+1 新年齡 from emp;

mysql> select name 姓名,age 舊年齡,age+1 新年齡 from emp limit 3;
+---------+-----------+-----------+
| 姓名    | 舊年齡    | 新年齡    |
+---------+-----------+-----------+
| yangsir |        42 |        43 |
| engo    |        38 |        39 |
| jerry   |        30 |        31 |
+---------+-----------+-----------+

條件:where

# 多條件協調操做導入:where 奇數 [group by 部門 having 平均薪資] order by [平均]薪資 limit 1

mysql>: select * from emp where id<5 limit 1;  # 正常
mysql>: select * from emp limit 1 where id<5;  # 異常,條件亂序

# 判斷規則
"""
比較符合:>  |  <  |  >=  |  <=  |  =  |  !=
區間符合:between 開始 and 結束 |  in(自定義容器)
    between 10 and 20:10~20
    in(10, 20, 30):10或20或30
邏輯符合:and  |  or  |  not
類似符合:like _|%,模糊匹配字符串,_表示一個字符,%表示任意字符
正則符合:regexp 正則語法
"""
mysql>: select * from emp where salary>5;
mysql>: select * from emp where id%2=0;

mysql>: select * from emp where salary between 6 and 9;

mysql>: select * from emp where id in(1, 3, 7, 20);

# _o 某o | __o 某某o | _o% 某o* (*是0~n個任意字符) | %o% *o*
mysql>: select * from emp where name like '%o%';
mysql>: select * from emp where name like '_o%';  
mysql>: select * from emp where name like '___o%';

# sql只支持部分正則語法
mysql>: select * from emp where name regexp '.*\d';  # 不支持\d表明數字,認爲\d就是普通字符串
mysql>: select * from emp where name regexp '.*[0-9]';  # 支持[]語法

where條件之正則匹配

# why: like完成模糊匹配, 但功能侷限, 能夠模糊個數, 但不能模糊類型, 正則能夠完成類型及個數的模糊匹配
'''
語法:字段 regexp '正則表達式'
注:只支持部分正則語法
'''
# 完成需求:
select * from emp where name regexp '.*[0-9]+.*';

分組與篩選:group by | having

where與having區別

# 表象:在沒有分組的狀況下,where與having結果相同
# 重點:having能夠對 聚合結果 進行篩選
mysql>: select * from emp where salary > 5;
mysql>: select * from emp having salary > 5;

mysql>: select * from emp where id in (5, 10, 15, 20);
mysql>: select * from emp having id in (5, 10, 15, 20);

聚合函數

"""
max():最大值
min():最小值
avg():平均值
sum():和
count():記數
group_concat():組內字段拼接,用來查看組內其餘字段
"""

如何分組之解決分組中思考題的過程

# res = select max(salary) '最高薪資', gender from emp where dep='教學部' group by gender;
# select name from emp where (salary 跟 res做比較)
# 一個查詢依賴於另外一個查詢的結果 => 一個查詢的結果做爲另一個查詢的條件 => 子查詢

分組查詢 group by

'''
分組:根據字段相同值造成不一樣的類別,不明確分組其實整個表就爲一個默認大組
緣由:把以值共性獲得的類別做爲考慮單位,再也不關係單條記錄,並且一組記錄

結果:只能考慮組內多條數據的聚會結果(聚合函數結果),分組的字段一樣是聚合結果,如:組內的最大最小值
'''
# 修改my.ini配置重啓mysql服務
sql_mode=ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION

# 在sql_mode沒有 ONLY_FULL_GROUP_BY 限制下,能夠執行,但結果沒有意義
# 有 ONLY_FULL_GROUP_BY 限制,報錯
mysql>: select * from emp group by dep;

# 分組後,表中數據考慮範圍就不是 單條記錄,由於每一個分組都包含了多條記錄,參照分組字段,對每一個分組中的 多條記錄 統一處理
# eg: 按部門分組,每一個部門都有哪些人、最高的薪資、最低的薪資、平均薪資、組裏一共有多少人

# 將多條數據統一處理,這種方式就叫 聚合
# 每一個部門都有哪些人、最高的薪資、最低的薪資、平均薪資 都稱之爲 聚合結果 - 聚合函數操做的結果
# 注:參與分組的字段,也歸於 聚合結果

mysql>: 
select 
    dep 部門,
    group_concat(name) 成員,
    max(salary) 最高薪資,
    min(salary) 最低薪資,
    avg(salary) 平均薪資,
    sum(salary) 總薪資,
    count(gender) 人數
from emp group by dep;

mysql>: select 
    dep 部門,
    max(age) 最高年齡
from emp group by dep;

# 總結:分組後,查詢條件只能爲 分組字段 和 聚合函數操做的聚合結果

分組後的having

mysql>: 
select 
    dep 部門,
    group_concat(name) 成員,
    max(salary) 最高薪資,
    min(salary) 最低薪資,
    avg(salary) 平均薪資,
    sum(salary) 總薪資,
    count(gender) 人數
from emp group by dep;

# 最低薪資小於2
mysql>:
select 
    dep 部門,
    group_concat(name) 成員,
    max(salary) 最高薪資,
    min(salary) 最低薪資,
    avg(salary) 平均薪資,
    sum(salary) 總薪資,
    count(gender) 人數
from emp group by dep having min(salary)<2;

# having能夠對 聚合結果 再進行篩選,where不能夠

排序order by

排序規則

# order by 主排序字段 [asc|desc], 次排序字段1 [asc|desc], ...次排序字段n [asc|desc]



升序:order by 字段名  asc
降序:order by 字段名 desc
多個排序條件:order by 字段名 asc,字段名 desc

未分組狀態下

mysql>: select * from emp;

# 按年齡升序
mysql>: select * from emp order by age asc;
# 按薪資降序
mysql>: select * from emp order by salary desc;

# 按薪資降序,若是相同,再按年齡降序
mysql>: select * from emp order by salary desc, age desc;
# 按齡降序,若是相同,再按薪資降序
mysql>: select * from emp order by age desc, salary desc;

分組狀態下

mysql>:
select 
    dep 部門,
    group_concat(name) 成員,
    max(salary) 最高薪資,
    min(salary) 最低薪資,
    avg(salary) 平均薪資,
    sum(salary) 總薪資,
    count(gender) 人數
from emp group by dep;

# 最高薪資降序
mysql:
select 
    dep 部門,
    group_concat(name) 成員,
    max(salary) 最高薪資,
    min(salary) 最低薪資,
    avg(salary) 平均薪資,
    sum(salary) 總薪資,
    count(gender) 人數
from emp group by dep
order by 最高薪資 desc;

限制 limit

# 語法:limit 條數  |  limit 偏移量,條數
mysql>: select name, salary from emp where salary<8 order by salary desc limit 1;

mysql>: select * from emp limit 5,3;  # 先偏移5條知足條件的記錄,再查詢3條

連表查詢

鏈接

# 鏈接:將有聯繫的多張表經過關聯(有聯繫就行,不必定是外鍵)字段,進行鏈接,形參一張大表
# 連表查詢:在大表的基礎上進行查詢,就稱之爲連表查詢

# 將表與表創建鏈接的方式有四種:內鏈接、左鏈接、右鏈接、全鏈接

一對多數據準備

mysql>: create database db3;
mysql>: use db3;

mysql>: 
create table dep(
    id int primary key auto_increment,
    name varchar(16),
    work varchar(16)
);
create table emp(
    id int primary key auto_increment,
    name varchar(16),
    salary float,
    dep_id int
);
insert into dep values(1, '市場部', '銷售'), (2, '教學部', '授課'), (3, '管理部', '開車');
insert into emp(name, salary, dep_id) values('egon', 3.0, 2),('yanghuhu', 2.0, 2),('sanjiang', 10.0, 1),('owen', 88888.0, 2),('liujie', 8.0, 1),('yingjie', 1.2, 0);

笛卡爾積

# 笛卡爾積: 集合 X{a, b} * Y{o, p, q} => Z{{a, o}, {a, p}, {a, q}, {b, o}, {b, p}, {b, q}}

mysql>: select * from emp, dep;

# 總結:是兩張表 記錄的全部排列組合,數據沒有利用價值


注意: 同時查詢兩張表造成新的表,能夠稱之爲虛擬表, 原表與表之間可能存在重複字段, 同時使用時須要明確所屬表,必要時還需明確所屬數據庫

內鏈接

# 關鍵字:inner join on
# 語法:from A表 inner join B表 on A表.關聯字段=B表.關聯字段

mysql>: 
select 
    emp.id,emp.name,salary,dep.name,work 
from emp inner join dep on emp.dep_id = dep.id 
order by emp.id;

# 總結:只保留兩個表有關聯的數據

左鏈接

# 關鍵字:left join on
# 語法:from 左表 left join 右表 on 左表.關聯字段=右表.關聯字段

mysql>: 
select 
    emp.id,emp.name,salary,dep.name,work 
from emp left join dep on emp.dep_id = dep.id 
order by emp.id;

# 總結:保留左表的所有數據,右表有對應數據直接連表顯示,沒有對應關係空填充

右鏈接

# 關鍵字:right join on
# 語法:from A表 right join B表 on A表.關聯字段=B表關聯字段

mysql>: 
select 
    emp.id,emp.name,salary,dep.name,work 
from emp right join dep on emp.dep_id = dep.id 
order by emp.id;

# 總結:保留右表的所有數據,左表有對應數據直接連表顯示,沒有對應關係空填充

左右能夠相互轉化

mysql>: 
select 
    emp.id,emp.name,salary,dep.name,work 
from emp right join dep on emp.dep_id = dep.id 
order by emp.id;

mysql>: 
select 
    emp.id,emp.name,salary,dep.name,work 
from dep left join emp on emp.dep_id = dep.id 
order by emp.id;

# 總結:更換一下左右表的位置,相對應更換左右鏈接關鍵字,結果相同

全鏈接

mysql>: 
select 
    emp.id,emp.name,salary,dep.name,work 
from emp left join dep on emp.dep_id = dep.id 

union

select 
    emp.id,emp.name,salary,dep.name,work 
from emp right join dep on emp.dep_id = dep.id 

order by id;

# 總結:左表右表數據都被保留,彼此有對應關係正常顯示,彼此沒有對應關係均空填充對方

一對一與一對多狀況一致

# 建立一對一 做者與做者詳情 表
create table author(
    id int,
    name varchar(64),
    detail_id int
);
create table author_detail(
    id int,
    phone varchar(11)
);
# 填充數據
insert into author values(1, 'Bob', 1), (2, 'Tom', 2), (3, 'ruakei', 0);
insert into author_detail values(1, '13344556677'), (2, '14466779988'), (3, '12344332255');

# 內連
select author.id,name,phone from author join author_detail on author.detail_id = author_detail.id order by author.id;

# 全連
select author.id,name,phone from author left join author_detail on author.detail_id = author_detail.id
union
select author.id,name,phone from author right join author_detail on author.detail_id = author_detail.id
order by id;

多對多:兩表兩表創建鏈接

# 在一對一基礎上,創建 做者與書 的多對多關係關係

# 利用以前的做者表
create table author(
    id int,
    name varchar(64),
    detail_id int
);
insert into author values(1, 'Bob', 1), (2, 'Tom', 2), (3, 'ruakei', 0);

# 建立新的書表
create table book(
    id int,
    name varchar(64),
    price decimal(5,2)
);
insert into book values(1, 'python', 3.66), (2, 'Linux', 2.66), (3, 'Go', 4.66);

# 建立 做者與書 的關係表
create table author_book(
    id int,
    author_id int,
    book_id int
);
# 數據:author-book:1-1,2  2-2,3  3-1,3
insert into author_book values(1,1,1),(2,1,2),(3,2,2),(4,2,3),(5,3,1),(6,3,3);

# 將有關聯的表一一創建鏈接,查詢因此本身所需字段
select book.name, book.price, author.name, author_detail.phone from book 
join author_book on book.id = author_book.book_id
join author on author_book.author_id = author.id
left join author_detail on author.detail_id = author_detail.id;

表查詢練習

一、查詢教學部山東人的平均薪資

select avg(salary) from emp 
    where area="山東" 
    group by dep 
    having dep="教學部";

select avg(salary) from emp
    where dep="教學部" 
    group by area
    having area="山東";

select avg(salary) from emp
    where dep="教學部" and area="山東";

二、查詢姓名中包含英文字母n而且居住在上海的人的全部信息

select * from emp
    where name like "%n%" and area="上海";

三、查詢姓名中包含英文字母n但不包含數字的人的全部信息

select * from emp 
    where  name like "%n%"  
    and name not  regexp '.\*[0-9].\*';

四、查看各部門的平均年齡並升序排序

select dep, avg(salary) '平均薪資' from emp 
    group by dep 
    order by avg(salary) asc;

五、查詢各部門中年紀最大的人的姓名與居住地(戶籍+區域)

select name, concat(area, '-', port), dep from emp 
    where (age, dep) in 
    (
        select max(age), dep from emp 
        group by dep
    );

六、查詢不一樣年齡層次平均薪資大於5w組中工資最高者的姓名與薪資

select name, salary  from emp 
    where (salary, age) in 
    (
        select  max(salary), age from emp 
        group by age 
        having avg(salary) > 5
    );

七、查詢每個部門下的員工們及員工職責

select max(dep.name), max(dep.work), group_concat(emp.name) from emp right join dep on emp.dep_id = dep.id group by dep_id;

聯合分組

# 數據來源:在單表emp下

# 聯合分組:按多個字段綜合結果進行分組

# 按 area與port組合後的結果進行分組,只有組合後的結果還一致,才認爲是一組
select group_concat(name),area,port from emp group by area,port;

子查詢

查詢結果輔助另一條sql的增刪改查。數據庫

若是查詢結果爲一條函數

where 字段 = (select 字段 from 表名)測試

若是查詢結果爲多條code

where 字段 in (select 字段 from 表名)

where 字段 > all(select 字段 from 表名)

where 字段 > any(select 字段 from 表名)

# 增:insert into 表 select子查詢
# 刪:delete from 表 條件是select子查詢(表不能與delete表相同)
# 查:select 字段 from 表 條件是select子查詢
# 改:update 表 set 字段=值 條件是select子查詢(表不能與update表相同)
# 數據來源:在單表emp下

# 子查詢:將一條查詢sql的結果做爲另外一條sql的條件

# 思考:每一個部門最高薪資的那我的全部信息

# 子查詢的sql
select dep, max(salary) from emp group by dep;
# 子查詢 - 查
select * from emp where (dep, salary) in (select dep, max(salary) from emp group by dep);

# 將子查詢轉換爲一張表
# 建立一個存子查詢數據的一張表
create table t1(dep_name varchar(64), max_salary decimal(5,2));
# 子查詢 - 增
insert into t1 select dep, max(salary) from emp group by dep;
# 需求
select name, dep_name, salary 
from emp join t1 
on emp.dep=t1.dep_name and emp.salary=t1.max_salary;

# 子查詢 - 改(update更新的表不能 與 子查詢select的表同表)
# 每一個部門最大薪資+1
update t1 set max_salary=max_salary+1;
# 給t1額外增長一個新部門
insert into t1 values ('打雜部', 100);
# 子查詢 - 改
update t1 set max_salary=max_salary+1 where dep_name in (select distinct dep from emp);
# 錯誤:update更新的表 與 子查詢select的表 相同
update t1 set max_salary=max_salary+1 where dep_name in (select distinct dep_name from t1);

# 子查詢 - 刪
delete from t1 where dep_name in (select distinct dep from emp);
# 錯誤: delete刪除的表 與 子查詢select的表 相同
delete from t1 where dep_name in (select distinct dep_name from t1);

all與any:區間修飾條件

# 語法規則
# where id in (1, 2, 3) => id是1或2或3
# where id not in (1, 2, 3) => id不是1,2,3
# where salary < all(3, 6, 9) => salary必須小於全部狀況(小於最小)
# where salary > all(3, 6, 9) => salary必須大於全部狀況(大於最大)
# where salary < any(3, 6, 9) => salary只要小於一種狀況(小於最大)
# where salary > any(3, 6, 9) => salary只要大於一種狀況(大於最小)
in < > ()
# 案例
select * from emp where salary < all(select salary from emp where id>11);
相關文章
相關標籤/搜索