MySQL基础

Posted 踏雪捕风

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了MySQL基础相关的知识,希望对你有一定的参考价值。

数据库

什么是数据库?

数据库是一个可以在一台机器上独立工作的,并且可以给我们提供高效、便捷的方式对数据进行增删改查的一种工具,数据库是长期存放在计算机内、有组织、可共享的数据集合

其本质就是一款基于网络通信的应用程序。

  • 程序稳定性

任意一台服务所在的机器崩溃了都不会影响数据和另外的服务。

  • 数据一致性

所有的数据都存储在一起,所有的程序操作的数据都是统一的,就不会出现数据不一致的现象。

  • 并发

数据库可以良好的支持并发,所有的程序操作数据库都是通过网络,而数据库本身支持并发的网络操作,不需要我们自己写socket

  • 高效率

使用数据库对数据进行增删改查的效率要高出我们自己处理文件很多。


  • 关系型数据库(数据之间彼此有关系或者约束,通常是以表格存储)

mysql、Oracle、db2、access、sql server

  • 非关系型数据库(通常是以k,v键值对的形式存储数据)

redis、mongodb、memcache


初识MySQL

任何基于网络通信的应用程序底层用的都是socket

  • 服务端

基于socket通信,收发消息,SQL语句操作。


  • 客户端

基于socket通信,收发消息,SQL语句操控。


"""
	库 	 <----> 文件夹
	表 	 <----> 文件
	记录 	<----> 文件内的数据
"""

  • 登录Mysql
mysql -uroot -p 	// 输入password回车即可
mysql -h 127.0.0.1 -P 3306 -uroot -p
  • 常见软件端口号
"""
	MySQL 3306
	redis 6379
	mongodb 27017
	django 8000
	flask 5000
"""

SQL语句初识

"""
	- MySQL中的sql语句是以分号作为结束的标志
	- 基本命令
		- show databases;   查看当前的库(文件夹)
		- 命令\\c;		不执行前面的命令,取消书写内容
		- quit    退出客户端
		  exit
"""

"""
	- 如何查看当前具体进程
		tasklist
		tasklist |findstr mysqld
    - 如何杀死具体的进程(管理员模式下)
    	taskkill /F /PID PID号
    - 查看编码方式
    	\\s

"""

"""
	- net start mysql   开启MYSQL服务 
	- net stop mysql	关闭MYSQL服务
	
	- mysqld --install   制作成系统服务
	- mysqld --remove    移除服务
	
"""

MySQL设置密码相关操作

  • 修改密码
mysqladmin -uroot -p 原密码 password 新的密码;    # 该命令直接在终端下输入即可

  • 跳过授权并重置密码
"""
	- 先关闭当前MySQL服务器
		终端下输入: mysqld --skip-grant-tables
    - 直接以无密码的方式连接
    	mysql -uroot -p   直接回车即可
    - 修改当前用户的密码
    	update mysql.user set password=password(新的密码) where
    	user=\'root\' and host=\'localhost\';
    - 立刻将修改数据刷到硬盘
    	flush privileges;
    - 关闭当前服务端,以正常校验授权表的形式启动服务端
"""

  • MySQL默认的配置文件
"""
	my-default.ini
		只要是.ini结尾的文件就是配置文件
		(程序启动的时候会先加载配置文件中的配置项)
		[mysqld]    # 一旦服务端启动就立即加载下面的配置项
		sql_mode=NO_ENGINE_SUBSTITUTION,STRICT_TRANS_TABLES 
		
		修改配置文件后要重启服务才能生效!!!!
"""

  • 统一编码的配置
[mysqld]
character-set-server=utf8
collation-server=utf8_general_ci
[client]
default-character-set=utf8
[mysql]
user=root  # 这里直接配置默认的登录账号和密码
password=123456
default-character-set=utf8

image-20210430173623257


基本SQL语句介绍

  • DDL语句 数据库定义语言: 数据库、表、视图、索引、存储过程,例如CREATE DROP ALTER
  • DML语句 数据库操纵语言: 插入数据INSERT、删除数据DELETE、更新数据UPDATE、查询数据SELECT
  • DCL语句 数据库控制语言: 例如控制用户的访问权限GRANT、REVOKE

  • 针对库的增删改查
# 增
create database db1;   # 创建一个名称位db1的库
create database db2 charset=\'gbk\';   # 指定库的编码方式

# 查
show databases;  # 查所有
show create database db1;  # 查指定的库

# 改
alter database db2 charset=\'utf-8\';  # 将db2的编码格式改为utf-8

# 删
drop database db2;   # 删除db2的库

  • 针对表的增删改查

操作表的时候,需要指定所在的库,即在哪个文件夹下创建表(即文件)。

# 查看当前所在的库
select database();

# 切换库
use db1;  # 切换到db1的库下

# 增
create table t1(id int, name char(4));  # 创建名称为t1的表
create table db2.t1(id int, name char(4));   # 采用绝对路径的方式创建表

# 查
show tables;  # 查看当前库下面所有的表名
show create table t1;  # 查看指定的表
desc t1;  # describe t1   常用该方法查看表数据

# 改
alter table t1 modify name char(16);  # 将name的限制长度改为16

# 删
drop table t1;

  • 针对数据的增删改查

一定要先有库,有表,最后才能操作记录。

# 增
insert into t1 values(1, \'jack\');
insert into t1 values(1, \'jack\'), (2, \'jack\'), (3, \'mary\');

# 查
select * from t1;  # 查看t1所有的内容 当数据量特别大的时候不建议使用 容易造成服务器数据加载崩溃
select id, name from t1;  # 将t1表中所有人的id,name字段显示
select name from t1;

# 改
update t1 set name=\'DSB\' where id>1;  # 将id>1的字段的name改为‘DSB’

# 删
delete from t1 where id>1;  # 将id大于1的数据全部删除
delete from t1 where name=\'jack\' and id=1;
delete from t1;  # 清空t1

存储引擎

存储引擎就是如何存储数据、如何为存储的数据建立索引和如何更新查询数据等技术的实现方法。

针对不同的数据应该有对应的不同处理机制来存储,存储引擎就是不同的处理机制。

  • MySQL主要存储引擎

Innodb

是MySQL5.5版本及之后的默认存储引擎,存储数据更加的安全。

Myisam

是MySQL5.5版本之前的默认存储引擎,不支持事务、表锁设计、支持全文索引,存储速度非常快,但是数据的安全性没Innodb好。

Memory

内存引擎,数据全部存放在内存中,断电即消失

Blackhole

黑洞存储引擎,可以应用于主备复制中的分发主库,无论存什么数据就立刻消失


# 查看数据库所有支持的存储引擎
show engines\\G;

# 不同的存储引擎在存储表的时候异同点
create table t1(id int) engine=innodb;  
# t1.frm --> 表结构   t1.idb ---> 表数据

create table t2(id int) engine=myisam;
# t2.frm ---> 表结构  t2.MYD ---> 表数据  t2.MYI ---> 表索引(目录)

create table t3(id int) engine=blackhole;
# t3.frm ---> 表结构

create table t4(id int) engine=memory;
# t4.frm ---> 表结构


# 插入数据
insert into t1 values(1);  # 1
insert into t2 values(1);  # 1
insert into t3 values(1);  # Empty set (0.00 sec)
insert into t4 values(1);  # 1   mysql服务端重启数据消失

表的操作

  • 创建表的完整语法
# 语法规则
create table 表名(
	字段名1 类型(宽度) 约束条件1 约束条件2 ...,
    字段名2 类型(宽度) 约束条件,
    字段名3 类型(宽度) 约束条件
);
# 表中最后一个字段不能加逗号


# 宽度
	- 指的是对存储数据的限制,默认宽度为1
# 约束条件
	- 约束条件是在宽度的基础之上增加额外的约束
  • 严格模式
# 如何查看严格模式
show variables like \'%mode\';  # 匹配结尾是mode的任意字符

==============================
模糊匹配:
	like
		%:匹配任意多个字符
		_:匹配任意单个字符
==============================

# 修改严格模式
set global sql_mode=\'STRICT_TRANS_TABLES\';
set session;   # 只在当前窗口有效
set global;    # 全局有效

  • 创建表的注意事项

1.在同一张表中字段名不能重复

2.宽度和约束条件可选

3.字段名和类型是必须的

  • 查看表结构
desc t1;  # describe 

show create table t1\\G;  # \\G  查看详细的表结构
  • 修改表结构
# 1. 修改表名
      ALTER TABLE 表名 
                          RENAME 新表名;

# 2. 增加字段
      ALTER TABLE 表名
                          ADD 字段名  数据类型 [完整性约束条件…],
                          ADD 字段名  数据类型 [完整性约束条件…];
      ALTER TABLE 表名
                          ADD 字段名  数据类型 [完整性约束条件…]  FIRST;
      ALTER TABLE 表名
                          ADD 字段名  数据类型 [完整性约束条件…]  AFTER 字段名;

# 3. 删除字段
      ALTER TABLE 表名 
                          DROP 字段名;

# 4. 修改字段
      ALTER TABLE 表名 
                          MODIFY  字段名 数据类型 [完整性约束条件…];
      ALTER TABLE 表名 
                          CHANGE 旧字段名 新字段名 旧数据类型 [完整性约束条件…];
      ALTER TABLE 表名 
                          CHANGE 旧字段名 新字段名 新数据类型 [完整性约束条件…];
  • 复制表
# 复制表结构+记录 (key不会复制: 主键、外键和索引)
mysql> create table new_service select * from service;

# 只复制表结构
mysql> select * from service where 1=2;        # 条件为假,查不到任何记录
Empty set (0.00 sec)
mysql> create table new1_service select * from service where 1=2;  
Query OK, 0 rows affected (0.00 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql> create table t4 like employees;
  • 删除表
DROP TABLE 表名;

数据类型

数值类型

image-20210501110112009


  • 整数类型

TINYINT SMALLINT MEDIUMINT INT BIGINT

作用:用于存储年龄、等级、id、号码等。

========================================
tinyint(m) unsigned zerofill
默认情况下带符号,超出限制只存最大可接受值
小整数,数据类型用于保存一些范围的整数数值范围

有符号:
-128 ~ 127
无符号:
0 ~ 255

约束条件:
unsigned    无符号

注:MySQL中无布尔值,使用tinyint(1)构造。



========================================
int(m) unsigned zerofill
数字超出m位正常显示,未超出则用0填充,无符号
		
整数,数据类型用于保存一些范围的整数数值范围

有符号:
-2147483648 ~ 2147483647
无符号:
0 ~ 4294967295
			
注:针对整型字段,括号内无需指定宽度,默认的范围足够显示  
            

========================================
bigint(m) unsigned zerofill
大整数,数据类型用于保存一些范围的整数数值范围

有符号:
-9223372036854775808 ~ 9223372036854775807
无符号:
0  ~  18446744073709551615


注意:

为该类型指定宽度时,仅仅只是指定查询结果的显示宽度,与存储范围无关,存储范围如下

其实我们完全没必要为整数类型指定显示宽度,使用默认即可,其默认的显示宽度,都是在最大值的基础上加1。

  • 浮点型

定点数类型DEC等同于DECIMAL

浮点类型:FLOATDOUBLE

作用:存储薪资、身高、体重、体质参数等

======================================
float(m,d) unsigned zerofill

定义:
单精度浮点数(非准确小数值),m是数字总个数,d是小数点后个数。
m最大值为255,d最大值为30

有符号:
           -3.402823466E+38 to -1.175494351E-38,
           1.175494351E-38 to 3.402823466E+38
无符号:
           1.175494351E-38 to 3.402823466E+38


精确度: 
           **** 随着小数的增多,精度变得不准确 ****
           
如:
	float(255,30)   # 总共255位,小数部分占30位


======================================
double(m,d) unsigned zerofill

定义:
双精度浮点数(非准确小数值),m是数字总个数,d是小数点后个数。
m最大值为255,d最大值为30

有符号:
           -1.7976931348623157E+308 to -2.2250738585072014E-308
           2.2250738585072014E-308 to 1.7976931348623157E+308

无符号:
           2.2250738585072014E-308 to 1.7976931348623157E+308

精确度:
           ****随着小数的增多,精度比float要高,但也会变得不准确 ****

======================================
decimal(m,d) unsigned zerofill

定义:
准确的小数值,m是数字总个数(负号不算),d是小数点后个数。
m最大值为65,d最大值为30。


精确度:
           **** 随着小数的增多,精度始终准确 ****
           对于精确数值计算时需要用此类型
           
decaimal能够存储精确值的原因在于其内部按照字符串存储。

精确度:float < double < decimal

字符类型


==========================================================
# char类型:定长,简单粗暴,浪费空间,存取速度快
    字符长度范围:0-255(一个中文是一个字符,是utf8编码的3个字节)
    存储:
        存储char类型的值时,会往右填充空格来满足长度
        例如:指定长度为10,存>10个字符则报错,存<10个字符则用空格填充直到凑够10个字符存储

    检索:
        在检索或者说查询时,查出的结果会自动删除尾部的空格,除非我们打开pad_char_to_full_length SQL模式(SET sql_mode = \'PAD_CHAR_TO_FULL_LENGTH\';


==========================================================
# varchar类型:变长,精准,节省空间,存取速度慢
    字符长度范围:0-65535(如果大于21845会提示用其他类型 。、
    mysql行最大限制为65535字节,字符编码为utf-8
    存储:
        varchar类型存储数据的真实内容,不会用空格填充,如果\'ab  \',尾部的空格也会被存起来
        
        强调:varchar类型会在真实数据前加1-2Bytes的前缀,该前缀用来表示真实数据的bytes字节数(1-2Bytes最大表示65535个数字,正好符合mysql对row的最大字节限制,即已经足够使用)
        如果真实的数据<255bytes则需要1Bytes的前缀(1Bytes=8bit 2**8最大表示的数字为255)
        如果真实的数据>255bytes则需要2Bytes的前缀(2Bytes=16bit 2**16最大表示的数字为65535)
        
        1bytes+jack  1bytes+mary  1bytes+json

    检索:
        尾部有空格会保存下来,在检索或者说查询时,也会正常显示包含空格在内的内容

  • char

定长,char(4)超过四个字符直接报错,不够则空格补全,浪费空间存取简单,直接按照固定的字符存取数据。

  • varchar

变长,varchar(4)超过四个字符直接报错,不够则有几个存几个,节省空间,存的时候需要制作报头,取得时候也需要读取报头,之后才读取真实的数据,存取较为麻烦

create table t18(name char(4));
create table t19(name varchar(4));

insert into t18 values(\'a\');
insert into t19 values(\'a\');
insert into t18 values(\'aaaa\');
insert into t19 values(\'aaaa\');

# char_length   统计字段长度
select char_length(name) from t18;
select char_length(name) from t19;

# char硬盘上存储的是真正的数据,带有空格的数据在显示的时候会被MySQL自动将多余的控股个剔除。

# 修改sql_mode,让MySQL不做自动剔除操作
set global sql_mode=\'STRICT_TRANS_TABLES,PAD_CHAR_TO_FULL_LENGTH\';

日期类型

  • 作用

存储用户注册时间,文章发布时间,员工入职时间,出生时间,过期时间等

  • 分类
date  年月日  2021-5-1
datetime 年月日时分秒 2021-5-1 12:12:12
time  时分秒  11:11:11
Year  年  2021

======================================
create table student(
	id int,
    name varchar(16),
    born_year year,
    birth_date date,
    study_time time,
    reg_time datetime
);

insert into student values(1, \'json\', \'2021\', \'2021-11-11\', \'11:11:11\',\'2021-11-11 11:11:11\');


======================================
mysql> select * from student;
+------+------+-----------+------------+------------+---------------------+
| id   | name | born_year | birth_date | study_time | reg_time            |
+------+------+-----------+------------+------------+---------------------+
|    1 | json |      2021 | 2021-11-11 | 11:11:11   | 2021-11-11 11:11:11 |
+------+------+-----------+------------+------------+---------------------+
1 row in set (0.00 sec)

mysql> desc student;
+------------+-------------+------+-----+---------+-------+
| Field      | Type        | Null | Key | Default | Extra |
+------------+-------------+------+-----+---------+-------+
| id         | int(11)     | YES  |     | NULL    |       |
| name       | varchar(16) | YES  |     | NULL    |       |
| born_year  | year(4)     | YES  |     | NULL    |       |
| birth_date | date        | YES  |     | NULL    |       |
| study_time | time        | YES  |     | NULL    |       |
| reg_time   | datetime    | YES  |     | NULL    |       |
+------------+-------------+------+-----+---------+-------+
6 rows in set (0.00 sec)

枚举与集合类型

  • 分类
enum	枚举	多选一
set		集合	多选多
  • 使用方式

枚举字段:只能在给定的范围内选一个值。

集合字段:在给定的范围内可以选择一个或一个以上的值。

create table user(
	id int, 
    name char(16),
    gender enum(\'male\', \'female\', \'others\'),
    hobby set(\'play\',\'music\',\'read\',\'study\')
);

insert into user values(1, \'json\', \'male\', \'play,music\');

====================================================
mysql> desc user;
+--------+------------------------------------+------+-----+---------+-------+
| Field  | Type                               | Null | Key | Default | Extra |
+--------+------------------------------------+------+-----+---------+-------+
| id     | int(11)                            | YES  |     | NULL    |       |
| name   | char(16)                           | YES  |     | NULL    |       |
| gender | enum(\'male\',\'female\',\'others\')     | YES  |     | NULL    |       |
| hobby  | set(\'play\',\'music\',\'read\',\'study\') | YES  |     | NULL    |       |
+--------+------------------------------------+------+-----+---------+-------+
4 rows in set (0.00 sec)

mysql> select * from user;
+------+------+--------+------------+
| id   | name | gender | hobby      |
+------+------+--------+------------+
|    1 | json | male   | play,music |
+------+------+--------+------------+
1 row in set (0.00 sec)

约束条件

"""
zerofill
unsigned
not null
"""
  • default默认值
# 插入数据的时候可以指定字段顺序
create table t1(
	id int,
    name char(18)
);

insert into t1(name, id) values(\'json\', 18);   # 不写字段则默认

==========================================
mysql> insert into t1(name, id) values(\'json\', 18);
Query OK, 1 row affected (0.02 sec)

mysql> select * from t1;
+------+------+
| id   | name |
+------+------+
|   18 | json |
+------+------+
1 row in set (0.00 sec)
===========================================
===========================================

create table t2(
	id int,
    name char(16) not null,
    gender enum(\'male\', \'female\', \'others\') default \'male\'
);   # 指定性别为多选一,默认值为male

insert into t2(id, name) values(1, \'json\');
insert into t2 values(2, \'tony\', \'female\');

==========================================
mysql> select * from t2;
+------+------+--------+
| id   | name | gender |
+------+------+--------+
|    1 | json | male   |
|    2 | tony | female |
+------+------+--------+
2 rows in set (0.00 sec)
===========================================


  • unique唯一
# - 单列唯一
create table t3(
	id int unique,
    name char(16)
);

insert into t3 values(1, \'json\'), (1, \'tony\');  
# ERROR 1062 (23000): Duplicate entry \'1\' for key \'id\'
insert into t3 values(1, \'json\'), (2, \'tony\');
# Query OK, 2 rows affected (0.00 sec)

=============================================
mysql> desc t3;
+-------+----------+------+-----+---------+-------+
| Field | Type     | Null | Key | Default | Extra |
+-------+----------+------+-----+---------+-------+
| id    | int(11)  | YES  | UNI | NULL    |       |
| name  | char(16) | YES  |     | NULL    |       |
+-------+----------+------+-----+---------+-------+
2 rows in set (0.00 sec)

mysql> select * from t3;
+------+------+
| id   | name |
+------+------+
|    1 | json |
|    2 | tony |
+------+------+
2 rows in set (0.00 sec)
===========================================
===========================================

# - 联合唯一
create table t4(
	id int,
    ip char(16),
    port int,
    unique(ip, port)
);    # unique(ip, port) 声明ip和port联合唯一

insert into t4 values(1, \'127.0.0.1\', 8080);
insert into t4 values(2, \'127.0.0.1\', 8081);
insert into t4 values(3, \'127.0.0.2\', 8080);
insert into t4 values(1, \'127.0.0.1\', 8080);
# ERROR 1062 (23000): Duplicate entry \'127.0.0.1-8080\' for key \'ip\'

=============================================
mysql> select * from t4;
+------+-----------+------+
| id   | ip        | port |
+------+-----------+------+
|    1 | 127.0.0.1 | 8080 |
|    2 | 127.0.0.1 | 8081 |
|    3 | 127.0.0.2 | 8080 |
+------+-----------+------+
3 rows in set (0.00 sec)

  • primary key主键

primary key字段的值不为空且唯一(等价于not null+unique),单列做主键,多列做主键(复合主键),但是一个表中只能有一个主键。

create table t5(id int primary key);
insert into t5 values(null); # ERROR 1048 (23000): Column \'id\' cannot be null
insert into t5 values(1); # Query OK, 1 row affected (0.02 sec)
insert into t5 values(1), (1); # ERROR 1062 (23000): Duplicate entry \'1\' for key \'PRIMARY\'

=======================================
mysql> desc t5;
+-------+---------+------+-----+---------+-------+
| Field | Type    | Null | Key | Default | Extra |
+-------+---------+------+-----+---------+-------+
| id    | int(11) | NO   | PRI | NULL    |       |
+-------+---------+------+-----+---------+-------+
1 row in set (0.00 sec)

mysql> select * from t5;
+----+
| id |
+----+
|  1 |
+----+
1 row in set (0.00 sec)

primary key除了有约束效果之外,它还是Innodb存储引擎组织数据的依据,Innodb存储引擎在创建表的时候必须要有primary key,类似于书的目录,能够帮助提升查询效率,也是建表的依据。

1、一张表中有且只有一个主键,若未设置则从上之下查找非空且唯一字段设定为主键。

2、若表中无主键且无非空且唯一字段,Innodb会将内部提供的隐藏字段作为主键。

3、一张表中通常都应该有一个主键字段,并且通常将id字段作为主键,即用于表示数据的编号。

联合主键:多个字段联合起来作为主键,本质上还是一个主键。

create table t7(
	ip char(16),
    port int,
    primary key(ip, port)
);

=========================
mysql> desc t7;
+-------+----------+------+-----+---------+-------+
| Field | Type     | Null | Key | Default | Extra |
+-------+----------+------+-----+---------+-------+
| ip    | char(16) | NO   | PRI | NULL    |       |
| port  | int(11)  | NO   | PRI | NULL    |       |
+-------+----------+------+-----+---------+-------+
2 rows in set (0.00 sec)
  • auto_increment自增

通常只能加在key键(即主键)上,不能给普通字段添加。

create table t8(
	id int primary key auto_increment,
    name varchar(16)
);

insert into t8(name) values(\'json\'), (\'tony\'), (\'kasen\');

========================================
mysql> desc t8;
+-------+-------------+------+-----+---------+----------------+
| Field | Type        | Null | Key | Default | Extra          |
+-------+-------------+------+-----+---------+----------------+
| id    | int(11)     | NO   | PRI | NULL    | auto_increment |
| name  | varchar(16) | YES  |     | NULL    |                |
+-------+-------------+------+-----+---------+----------------+
2 rows in set (0.00 sec)

mysql> select * from t8;
+----+-------+
| id | name  |
+----+-------+
|  1 | json  |
|  2 | tony  |
|  3 | kasen |
+----+-------+
3 rows in set (0.00 sec)
===========================================
===========================================

delete from t8;  # 在删除表中数据的时候,主键的自增不会停止
truncate t8;  # 清空表中的数据,并重置主键,直接从零开始

=======================================
mysql> delete from t8;
Query OK, 3 rows affected (0.02 sec)

mysql> insert into t8(name) values(\'json\'), (\'jack\');
Query OK, 2 rows affected (0.02 sec)
Records: 2  Duplicates: 0  Warnings: 0

mysql> select * from t8;
+----+------+
| id | name |
+----+------+
|  4 | json |
|  5 | jack |
+----+------+
2 rows in set (0.00 sec)

mysql> truncate t8;
Query OK, 0 rows affected (0.04 sec)

mysql> insert into t8(name) values(\'json\'), (\'jack\');
Query OK, 2 rows affected (0.02 sec)
Records: 2  Duplicates: 0  Warnings: 0

mysql> select * from t8;
+----+------+
| id | name |
+----+------+
|  1 | json |
|  2 | jack |
+----+------+
2 rows in set (0.00 sec)

小结

以后在创建表的id(即数据的唯一标识)字段的时候一定要加primary key auto_increment

表与表之间的关系

foreign key外键用于建立表与表之间特殊关系。

表关系分析步骤

# 1、先站在左表的角度去找
是否左表的多条记录可以对应右表的一条记录,如果是,则证明左表的一个字段foreign key 右表一个字段(通常是id)

# 2、再站在右表的角度去找
是否右表的多条记录可以对应左表的一条记录,如果是,则证明右表的一个字段foreign key 左表一个字段(通常是id)
  • 一对多关系

单向的一对多的成立,外键字段建在的地方,创建表的时候先建被关联表,在数据录入的时候先录入被关联表,关联方式 foreign key, 在MySQL中没有多对一概念。

# 部门表  ----> 被关联表
create table dep(
	id int primary key auto_increment,
    dep_name char(16),
    dep_desc char(32)
);

# 员工表 ----> 关联表
create table emp(
	id int primary key auto_increment,
    name char(16),
    gender enum(\'male\', \'female\', \'others\') default \'male\',
    dep_id int,
    foreign key(dep_id) references dep(id)
);

=================================================
mysql> desc dep;
+----------+----------+------+-----+---------+----------------+
| Field    | Type     | Null | Key | Default | Extra          |
+----------+----------+------+-----+---------+----------------+
| id       | int(11)  | NO   | PRI | NULL    | auto_increment |
| dep_name | char(16) | YES  |     | NULL    |                |
| dep_desc | char(32) | YES  |     | NULL    |                |
+----------+----------+------+-----+---------+----------------+
3 rows in set (0.00 sec)

mysql> desc emp;
+--------+--------------------------------+------+-----+---------+----------------+
| Field  | Type                           | Null | Key | Default | Extra          |
+--------+--------------------------------+------+-----+---------+----------------+
| id     | int(11)                        | NO   | PRI | NULL    | auto_increment |
| name   | char(16)                       | YES  |     | NULL    |                |
| gender | enum(\'male\',\'female\',\'others\') | YES  |     | male    |                |
| dep_id | int(11)                        | YES  | MUL | NULL    |                |
+--------+--------------------------------+------+-----+---------+----------------+
4 rows in set (0.00 sec)
===========================================
===========================================

insert into dep(dep_name, dep_desc) values(\'技术部\',\'我写的程序,没有BUG!\'), (\'运维部\',\'今天服务器又崩了!\');
insert into emp(name, dep_id) values(\'json\', 1), (\'tony\', 2), (\'jack\',1);

===========================================
mysql> select * from dep;
+----+-----------+--------------------------------+
| id | dep_name  | dep_desc                       |
+----+-----------+--------------------------------+
|  1 | 技术部    | 我写的程序,没有BUG!          |
|  2 | 运维部    | 今天服务器又崩了!             |
+----+-----------+--------------------------------+
2 rows in set (0.00 sec)

mysql> select * from emp;
+----+------+--------+--------+
| id | name | gender | dep_id |
+----+------+--------+--------+
|  1 | json | male   |      1 |
|  2 | tony | male   |      2 |
|  3 | jack | male   |      1 |
+----+------+--------+--------+
3 rows in set (0.00 sec)

同步更新和删除:级联更新、级联删除,添加on update cascade on delete cascade字段。

# 部门表  ----> 被关联表
create table dep(
	id int primary key auto_increment,
    dep_name char(16),
    dep_desc char(32)
);

# 员工表 ----> 关联表
create table emp(
	id int primary key auto_increment,
    name char(16),
    gender enum(\'male\', \'female\', \'others\') default \'male\',
    dep_id int,
    foreign key(dep_id) references dep(id) 
    on update cascade 
    on delete cascade
);

insert into dep(dep_name, dep_desc) values(\'技术部\',\'我写的程序,没有BUG!\'), (\'运维部\',\'今天服务器又崩了!\');
insert into emp(name, dep_id) values(\'json\', 1), (\'tony\', 2), (\'jack\',1);

update dep set id=200 where id=1;  # 将部门表中id=1改为200,员工表同步更新

===========================================
mysql> select * from dep;
+-----+-----------+--------------------------------+
| id  | dep_name  | dep_desc                       |
+-----+-----------+--------------------------------+
|   2 | 运维部    | 今天服务器又崩了!             |
| 200 | 技术部    | 我写的程序,没有BUG!          |
+-----+-----------+--------------------------------+
2 rows in set (0.00 sec)

mysql> select * from emp;
+----+------+--------+--------+
| id | name | gender | dep_id |
+----+------+--------+--------+
|  1 | json | male   |    200 |
|  2 | tony | male   |      2 |
|  3 | jack | male   |    200 |
+----+------+--------+--------+
3 rows in set (0.00 sec)
  • 多对多关系

双向的一对多,即多对多,关联方式:foreign key+一张新表,即创建用户表 + 关系表 + 用户表。

# 图书表
create table book(
	id int primary key auto_increment,
    title varchar(32),
    price int
);

# 作者表
create table author(
	id int primary key auto_increment,
    name varchar(32),
    age int
);

# 关系表  ----> 中间关系
create table book2author(
	id int primary key auto_increment,
    book_id int not null,
    author_id int not null,
    foreign key(book_id) references book(id)
    on update cascade
    on delete cascade,
    foreign key(author_id) references author(id)
    on update cascade
    on delete cascade
);

insert into book(title, price) values(\'python\', 666), (\'5G技术\', 100);
insert into author(name, age) values(\'json\', 12), (\'tony\',18);
insert into book2author(book_id, author_id) values(1, 2),(2,1),(1,1);

================================================
mysql> select * from book;
+----+----------+-------+
| id | title    | price |
+----+----------+-------+
|  1 | python   |   666 |
|  2 | 5G技术   |   100 |
+----+----------+-------+
2 rows in set (0.00 sec)

mysql> select * from author;
+----+------+------+
| id | name | age  |
+----+------+------+
|  1 | json |   12 |
|  2 | tony |   18 |
+----+------+------+
2 rows in set (0.00 sec)

mysql> select * from book2author;
+----+---------+-----------+
| id | book_id | author_id |
+----+---------+-----------+
|  1 |       1 |         2 |
|  2 |       2 |         1 |
|  3 |       1 |         1 |
+----+---------+-----------+
3 rows in set (0.00 sec)
  • 一对一关系

如果1和2都不成立,而是左表的一条记录唯一对应右表的一条记录,反之亦然。这种情况很简单,就是在左表foreign key右表的基础上,将左表的外键字段设置成unique即可,关联方式:foreign key+unique

"""
id name age addr phone hobby ....
表的信息包括了用户基础信息和详细信息,那么就分为用户表和用户详情表
即:
	- 用户表
		id name age
	- 用户详情表
		id addr phone hobby email...
		
    站在用户表
    	一个用户能否对应多个详情表   ---> 不能
    站在详情表
    	一个详情能否对应多个用户表   ---> 不能
    	
    结论:
    	单向的一对一都不成立,那么两个表的关系就是一对一,或者是没有关系
"""
  • 演示
# 用户详情表
create table authordetail(
	id int primary key auto_increment,
    phone int,
    addr varchar(32)
);

# 用户表
create table authors(
	id int primary key auto_increment,
    name varchar(32),
    age int, 
    authordetail_id int unique,
    foreign key(authordetail_id) references authordetail(id)
    on update cascade
    on delete cascade
);

=======================================
mysql> desc authordetail;
+-------+-------------+------+-----+---------+----------------+
| Field | Type        | Null | Key | Default | Extra          |
+-------+-------------+------+-----+---------+----------------+
| id    | int(11)     | NO   | PRI | NULL    | auto_increment |
| phone | int(11)     | YES  |     | NULL    |                |
| addr  | varchar(32) | YES  |     | NULL    |                |
+-------+-------------+------+-----+---------+----------------+
3 rows in set (0.00 sec)

mysql> desc authors;
+-----------------+-------------+------+-----+---------+----------------+
| Field           | Type        | Null | Key | Default | Extra          |
+-----------------+-------------+------+-----+---------+----------------+
| id              | int(11)     | NO   | PRI | NULL    | auto_increment |
| name            | varchar(32) | YES  |     | NULL    |                |
| age             | int(11)     | YES  |     | NULL    |                |
| authordetail_id | int(11)     | YES  | UNI | NULL    |                |
+-----------------+-------------+------+-----+---------+----------------+
4 rows in set (0.00 sec)

小结

1、一对多:外键字段建在多的一方

2、多对多:开设一张关系表建立外键

3、一对一:外键字段建在查询频率高的一方

修改表的完整语法

# - 修改表名
alter table 表名 rename 新表名;

# - 增加字段
alter table 表名 add 字段名 字段类型(宽度) 约束条件;
alter table 表名 add 字段名 字段类型(宽度) 约束条件 first; # 添加到最前面
alter table 表名 add 字段名 字段类型(宽度) 约束条件 last 字段名; # 添加到某字段后面

# - 删除字段
alter table 表名 drop 字段名;

# - 修改字段
alter table 表名 modify 字段名 字段类型(宽度) 约束条件;
alter table 表名 change 旧字段名 新字段名 字段类型(宽度) 约束条件;

复制表

SQL语句的结果就是一张虚拟表。

# 复制表结构+记录,key不会复制: 主键、外键和索引
create table 新表名 select * from 旧表名;  # 能复制字段和数据  不能复制键

create table new_table select * from dep;
create table new_table select * from dep where id>100;

======================================
mysql> desc new_table;
+----------+----------+------+-----+---------+-------+
| Field    | Type     | Null | Key | Default | Extra |
+----------+----------+------+-----+---------+-------+
| id       | int(11)  | NO   |     | 0       |       |
| dep_name | char(16) | YES  |     | NULL    |       |
| dep_desc | char(32) | YES  |     | NULL    |       |
+----------+----------+------+-----+---------+-------+
3 rows in set (0.00 sec)

mysql> desc dep;
+----------+----------+------+-----+---------+----------------+
| Field    | Type     | Null | Key | Default | Extra          |
+----------+----------+------+-----+---------+----------------+
| id       | int(11)  | NO   | PRI | NULL    | auto_increment |
| dep_name | char(16) | YES  |     | NULL    |                |
| dep_desc | char(32) | YES  |     | NULL    |                |
+----------+----------+------+-----+---------+----------------+
3 rows in set (0.00 sec)

表准备

create table emp(
  id int not null unique auto_increment,
  name varchar(20) not null,
  sex 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
);

#插入记录
#三个部门:教学,销售,运营
insert into emp(name,sex,age,hire_date,post,salary,office,depart_id) values
(\'jason\',\'male\',18,\'20170301\',\'张江第一帅形象代言\',7300.33,401,1), #以下是教学部
(\'tom\',\'male\',78,\'20150302\',\'teacher\',1000000.31,401,1),
(\'kevin\',\'male\',81,\'20130305\',\'teacher\',8300,401,1),
(\'tony\',\'male\',73,\'20140701\',\'teacher\',3500,401,1),
(\'owen\',\'male\',28,\'20121101\',\'teacher\',2100,401,1),
(\'jack\',\'female\',18,\'20110211\',\'teacher\',9000,401,1),
(\'jenny\',\'male\',18,\'19000301\',\'teacher\',30000,401,1),
(\'sank\',\'male\',48,\'20101111\',\'teacher\',10000,401,1),
(\'哈哈\',\'female\',48,\'20150311\',\'sale\',3000.13,402,2),#以下是销售部门
(\'呵呵\',\'female\',38,\'20101101\',\'sale\',2000.35,402,2),
(\'西西\',\'female\',18,\'20110312\',\'sale\',1000.37,402,2),
(\'乐乐\',\'female\',18,\'20160513\',\'sale\',3000.29,402,2),
(\'拉拉\',\'female\',28,\'20170127\',\'sale\',4000.33,402,2),
(\'僧龙\',\'male\',28,\'20160311\',\'operation\',10000.13,403,3), #以下是运营部门
(\'程咬金\',\'male\',18,\'19970312\',\'operation\',20000,403,3),
(\'程咬银\',\'female\',18,\'20130311\',\'operation\',19000,403,3),
(\'程咬铜\',\'male\',18,\'20150411\',\'operation\',18000,403,3),
(\'程咬铁\',\'female\',18,\'20140512\',\'operation\',17000,403,3);

当表字段特别多的时候,展示方法:

select * from emp\\G;   # 分行展示

插入中文乱码问题解决:

Windows在修改编码后仍然出现乱码或者显示为空白的问题,可将编码改成GBK格式。

关键字的执行顺序

# 书写顺序
select id,name from emp where id > 3;

# 执行顺序
from ---> where ---> select

======================================
先用slect * from --->占位,后续补充sql语句即可
======================================
# 关键字执行优先级
from  	--->  找到表
where	--->  指定约束条件,去表中取出记录
group by  ---->   将取出的结果进行分组
having   ---->   将分组的结果进行过滤
select   ---->   执行select查询语句
distinct  --->   去重
order by  --->   将结果按照条件进行排序
limit   ---->    限制结果的显示条数

  • where约束条件

对整体数据的筛选操作

"""
比较运算符:><>= <= <> !=
between 80 and 100 值在80到100之间
in(80,90,100) 值是80或90或100

模糊查询
	like
		- % 匹配任意多个字符
		- _ 匹配任意单个字符

逻辑运算符:在多个条件直接可以使用逻辑运算符 and or not
"""

# 1.查询id大于等于3小于等于6的数据
select id, name from emp where id >= 3 and id <=6;
select id, name from emp where id between 3 and 6;
***************************************************
mysql> select id, name from emp where id >= 3 and id <=6;
+----+-------+
| id | name  |
+----+-------+
|  3 | kevin |
|  4 | tony  |
|  5 | owen  |
|  6 | jack  |
+----+-------+
4 rows in set (0.00 sec)
=================================================
=================================================

# 2.查询薪资是20000或者18000或者17000的数据
select id, name, salary from emp where salary=20000 or salary=18000 or salary=17000;
select id, name, salary from emp where salary in (20000,18000,17000);
***************************************************
mysql> select id, name, salary from emp where salary in (20000,18000,17000);
+----+-----------+----------+
| id | name      | salary   |
+----+-----------+----------+
| 15 | 程咬金    | 20000.00 |
| 17 | 程咬铜    | 18000.00 |
| 18 | 程咬铁    | 17000.00 |
+----+-----------+----------+
3 rows in set (0.00 sec)
=================================================
=================================================

# 3.查询员工姓名中包含字母o的员工的姓名和薪资
select id, name, salary from emp where name like \'%o%\';  # 表示o的前后可以出现任意字符
***************************************************
mysql> select id, name, salary from emp where name like \'%o%\';
+----+-------+------------+
| id | name  | salary     |
+----+-------+------------+
|  1 | jason |    7300.33 |
|  2 | tom   | 1000000.31 |
|  4 | tony  |    3500.00 |
|  5 | owen  |    2100.00 |
+----+-------+------------+
4 rows in set (0.00 sec)

=================================================
=================================================

# 4.查询员工姓名是由四个字符组成的 姓名和薪资  char_length()
select id, name, salary from emp where name like \'____\';
select id, name, salary from emp where char_length(name) = 4;
***************************************************
mysql> select id, name, salary from emp where name like \'____\';
+----+------+----------+
| id | name | salary   |
+----+------+----------+
|  4 | tony |  3500.00 |
|  5 | owen |  2100.00 |
|  6 | jack |  9000.00 |
|  8 | sank | 10000.00 |
+----+------+----------+
4 rows in set (0.00 sec)

=================================================
=================================================

# 5.查询id小于3或者id大于6的数据
select id, name from emp where id not between 3 and 6;
=================================================
=================================================

# 6.查询薪资不在20000,18000,17000范围的数据
select * from emp where salary not in (20000, 18000, 17000);
=================================================
=================================================

# 7.查询岗位描述为空的员工姓名和岗位名  针对null不用等号 用is
select name,post from emp where post_comment is NULL;

  • group by分组

设置严格模式:set global sql_mode = \'strict_trans_tables,only_full_group_by\';

设置严格模式之后,分组,默认只能拿到分组的依据,按照什么分组就只能拿到分组的字段,其他字段不能直接获取,需要借助于一些方法(聚合函数)。

聚合函数

max、min、sum、count、avg。


# 按照部门分组
select post from emp group by post; 

======================================
======================================
# 1.获取每个部门的最高薪资 --> 每个部门 --> 需要分组
select post,max(salary) from emp group by post;
select post as \'部门\',max(salary) as \'最高薪资\' from emp group by post;
select post \'部门\',max(salary) \'最高薪资\' from emp group by post;
*************************************
mysql> select post \'部门\',max(salary) \'最高薪资\' from emp group by post;
+-----------------------------+--------------+
| 部门                        | 最高薪资     |
+-----------------------------+--------------+
| operation                   |     20000.00 |
| sale                        |      4000.33 |
| teacher                     |   1000000.31 |
| 张江第一帅形象代言          |      7300.33 |
+-----------------------------+--------------+
4 rows in set (0.00 sec)

======================================
======================================
# 2.获取每个部门的最低薪资
select post,min(salary) from emp group by post;
=======================================
=======================================

# 3.获取每个部门的平均薪资
select post,avg(salary) from emp group by post;
=======================================
=======================================

# 4.获取每个部门的工资总和
select post,sum(salary) from emp group by post;
=======================================
=======================================

# 5.获取每个部门的人数
select post,count(id) from emp group by post;  # 常用方法
select post,count(salary) from emp group by post;
select post,count(age) from emp group by post;
select post,count(post_comment) from emp group by post;  # null的内容不能进行计数
=======================================
=======================================

# 6.查询分组之后的部门名称和每个部门下所有的员工姓名 
# group_concat不单单可以支持你获取分组之后的其他字段值 还支持拼接操作
select post,group_concat(name) from emp group by post;
select post,group_concat(name,\'_DSB\') from emp group by post;
select post,group_concat(name,\':\',salary) from emp group by post;

# concat不分组的时候用 
select concat(\'NAME:\',name),concat(\'SAL:\',salary) from emp;
========================================
========================================
# 7.查询每个人的年薪(salary*12)
select name,salary*12 from emp;

========================================
========================================

# 8.给临时表起别名
select t1.id,t1.name from emp as t1;

注意:

"""
关键字where和group by同时出现的时候group by必须在where的后面
    - where先对整体数据进行过滤之后再分组操作
    - where筛选条件不能使用聚合函数
"""
select id,name,age from emp where max(salary) > 3000;
# ERROR 1111 (HY000): Invalid use of group function

select max(salary) from emp;  # 不分组 默认整体就是一组
******************************
mysql> select max(salary) from emp;
+-------------+
| max(salary) |
+-------------+
|  1000000.31 |
+-------------+
1 row in set (0.00 sec)

======================================
======================================

# 统计各部门年龄在30岁以上的员工平均薪资
	1 先求所有年龄大于30岁的员工
    	select * from emp where age>30;
    2 再对结果进行分组
     	select * from emp where age>30 group by post;
    
    3 完整语法 
    	select post,avg(salary) from emp where age>30 group by post;
        select post as \'部门\',avg(salary) as \'平均薪资\' from emp where age>30 group by post;
  • having分组之后的筛选

having的语法同where是一致的,只不过having是在分组之后进行的过滤操作,即having可以直接使用聚合函数。

# 统计各部门年龄在30岁以上的员工平均工资并且保留平均薪资大于10000的部门
select post,avg(salary) from emp 
		where age>30 
    	group by post
        having avg(salary) > 10000
        ;
***************************************
mysql> select post,avg(salary) from emp
    -> where age>30
    ->     group by post
    ->         having avg(salary) > 10000
    ->         ;
+---------+---------------+
| post    | avg(salary)   |
+---------+---------------+
| teacher | 255450.077500 |
+---------+---------------+
1 row in set (0.00 sec)

  • distinct去重

必须是完全一样的数据才能去重,注意数据的主键(id)是不一样的,在查询的时候一定不要查询主键,否则不能去重。

select distinct id, age from emp;  # 带主键没办法去重
select distinct age from emp;  # 根据年龄数据进行去重

  • order by排序

asc(升序,默认不写)、desc(降序)。

# 先按照age降序,若age相同,则按照salary升序
select * from emp order by age desc,salary asc;

===========================================
===========================================

# 统计各部门年龄在10岁以上的员工平均工资并且保留平均薪资大于1000的部门,然后对平均工资降序排序
select post,avg(salary) from emp 
		where age>10 
    	group by post
        having avg(salary) > 1000
        order by avg(salary) desc
        ;
        
  • limit限制展示条数
select * from emp limit 起始位置, 展示条数;

=========================================
=========================================

select * from emp limit 5, 10;  # id从6开始显示到15

正则表达式

select * from emp where name regexp \'^j.*(n|y)$\';
# 显示name以j开头,以n或者y结尾,中间为任意多个字符

多表查询

建表

#建表
create table dep(
id int,
name varchar(20) 
);

create table emp(
id int primary key auto_increment,
name varchar(20),
sex enum(\'male\',\'female\') not null default \'male\',
age int,
dep_id int
);

#插入数据
insert into dep values
(200,\'技术\'),
(201,\'人力资源\'),
(202,\'销售\'),
(203,\'运营\');

insert into emp(name,sex,age,dep_id) values
(\'jason\',\'male\',18,200),
(\'egon\',\'female\',48,201),
(\'kevin\',\'male\',18,201),
(\'nick\',\'male\',28,202),
(\'owen\',\'male\',18,203),
(\'jerry\',\'female\',18,204);

表查询

  • 笛卡尔积
select * from dep, emp;   # 进行了一对四的数据拼接
******************************
mysql> select * from dep, emp;
+------+--------------+----+-------+--------+------+--------+
| id   | name         | id | name  | sex    | age  | dep_id |
+------+--------------+----+-------+--------+------+--------+
|  200 | 技术         |  1 | jason | male   |   18 |    200 |
|  201 | 人力资源     |  1 | jason | male   |   18 |    200 |
|  202 | 销售         |  1 | jason | male   |   18 |    200 |
|  203 | 运营         |  1 | jason | male   |   18 |    200 |
|  200 | 技术         |  2 | egon  | female |   48 |    201 |
|  201 | 人力资源     |  2 | egon  | female |   48 |    201 |
|  202 | 销售         |  2 | egon  | female |   48 |    201 |
|  203 | 运营         |  2 | egon  | female |   48 |    201 |
|  200 | 技术         |  3 | kevin | male   |   18 |    201 |
|  201 | 人力资源     |  3 | kevin | male   |   18 |    201 |
|  202 | 销售         |  3 | kevin | male   |   18 |    201 |
|  203 | 运营         |  3 | kevin | male   |   18 |    201 |
|  200 | 技术         |  4 | nick  | male   |   28 |    202 |
|  201 | 人力资源     |  4 | nick  | male   |   28 |    202 |
|  202 | 销售         |  4 | nick  | male   |   28 |    202 |
|  203 | 运营         |  4 | nick  | male   |   28 |    202 |
|  200 | 技术         |  5 | owen  | male   |   18 |    203 |
|  201 | 人力资源     |  5 | owen  | male   |   18 |    203 |
|  202 | 销售         |  5 | owen  | male   |   18 |    203 |
|  203 | 运营         |  5 | owen  | male   |   18 |    203 |
|  200 | 技术         |  6 | jerry | female |   18 |    204 |
|  201 | 人力资源     |  6 | jerry | female |   18 |    204 |
|  202 | 销售         |  6 | jerry | female |   18 |    204 |
|  203 | 运营         |  6 | jerry | female |   18 |    204 |
+------+--------------+----+-------+--------+------+--------+
24 rows in set (0.00 sec)

  • 查询emp的id与dep_id对应的数据
select * from emp,dep where emp.dep_id = dep.id;
****************************************************
mysql> select * from emp,dep where emp.dep_id = dep.id;
+----+-------+--------+------+--------+------+--------------+
| id | name  | sex    | age  | dep_id | id   | name         |
+----+-------+--------+------+--------+------+--------------+
|  1 | jason | male   |   18 |    200 |  200 | 技术         |
|  2 | egon  | female |   48 |    201 |  201 | 人力资源     |
|  3 | kevin | male   |   18 |    201 |  201 | 人力资源     |
|  4 | nick  | male   |   28 |    202 |  202 | 销售         |
|  5 | owen  | male   |   18 |    203 |  203 | 运营         |
+----+-------+--------+------+--------+------+--------------+
5 rows in set (0.00 sec)

  • 拼表操作

inner join内连接、left join左连接、right join右连接、union全连接。

# inner join  内连接
select * from emp inner join dep on emp.dep_id = dep.id;
# 只拼接两张表中公有的数据部分
**************************************************
mysql> select * from emp inner join dep on emp.dep_id = dep.id;
+----+-------+--------+------+--------+------+--------------+
| id | name  | sex    | age  | dep_id | id   | name         |
+----+-------+--------+------+--------+------+--------------+
|  1 | jason | male   |   18 |    200 |  200 | 技术         |
|  2 | egon  | female |   48 |    201 |  201 | 人力资源     |
|  3 | kevin | male   |   18 |    201 |  201 | 人力资源     |
|  4 | nick  | male   |   28 |    202 |  202 | 销售         |
|  5 | owen  | male   |   18 |    203 |  203 | 运营         |
+----+-------+--------+------+--------+------+--------------+
5 rows in set (0.00 sec)

==================================================
==================================================

# left join   左连接
select * from emp left join dep on emp.dep_id = dep.id;
# 左表所有的数据都展示出来 没有对应的项就用NULL
***************************************************

# right join  右连接
select * from emp right join dep on emp.dep_id = dep.id;
# 右表所有的数据都展示出来 没有对应的项就用NULL
***************************************************

# union		全连接  左右两表所有的数据都展示出来
select * from emp left join dep on emp.dep_id = dep.id
union
select * from emp right join dep on emp.dep_id = dep.id;

子查询

1.子查询是将一个查询语句嵌套在另一个查询语句中。
2.内层查询语句的查询结果,可以为外层查询语句提供查询条件。
3.子查询中可以包含:IN、NOT IN、ANY、ALL、EXISTS 和 NOT EXISTS等关键字
4.还可以包含比较运算符:= 、 !=、> 、<等


即:将一个语句的查询结果当作另一个语句的查询条件。


# 查询部门是技术或者人力资源的员工信息
	1 先获取部门的id号
    select id from dep where name = \'技术\' or name = \'人力资源\'
    2 再去员工表里面筛选出对应的员工
    select name from emp where dep_id in (200, 201);
	3 完整语法:
select * from emp where dep_id in (select id from dep where name = \'技术\' or name = \'人力资源\');
********************************************************
mysql> select * from emp where dep_id in (select id from dep where name = \'技术\' or name = \'人力资源\');
+----+-------+--------+------+--------+
| id | name  | sex    | age  | dep_id |
+----+-------+--------+------+--------+
|  1 | jason | male   |   18 |    200 |
|  2 | egon  | female |   48 |    201 |
|  3 | kevin | male   |   18 |    201 |
+----+-------+--------+------+--------+
3 rows in set (0.00 sec)

小结:

表的查询结果可以作为其他表的查询条件,也可以通过起别名的方式把它作为一个张虚拟表根其他表关联,同时,多表查询的两种方式为先拼接表再查询,或者通过子查询进行分步查询。

综合应用

-- 1、查询所有的课程的名称以及对应的任课老师姓名
-- SELECT
-- 	course.cname,
-- 	teacher.tname 
-- FROM
-- 	course
-- 	INNER JOIN teacher ON course.teacher_id = teacher.tid;

-- 4、查询平均成绩大于八十分的同学的姓名和平均成绩
-- SELECT
-- 	student.sname,
-- 	t1.avg_num 
-- FROM
-- 	student
-- 	INNER JOIN (
-- 	SELECT
-- 		score.student_id,
-- 		avg( num ) AS avg_num 
-- 	FROM
-- 		score
-- 		INNER JOIN student ON score.student_id = student.sid 
-- 	GROUP BY
-- 		score.student_id 
-- 	HAVING
-- 		AVG( num ) > 80 
-- 	) AS t1 ON student.sid = t1.student_id;


-- 7、 查询没有报李平老师课的学生姓名
# 分步操作
# 1 先找到李平老师教授的课程id
# 2 再找所有报了李平老师课程的学生id
# 3 之后去学生表里面取反 就可以获取到没有报李平老师课程的学生姓名
-- SELECT
-- 	student.sname 
-- FROM
-- 	student 
-- WHERE
-- 	sid NOT IN (
-- 	SELECT DISTINCT
-- 		score.student_id 
-- 	FROM
-- 		score 
-- 	WHERE
-- 		score.course_id IN ( SELECT course.cid FROM teacher INNER JOIN course ON teacher.tid = course.teacher_id WHERE teacher.tname = \'李平老师\' ) 
-- 	);

-- 8、 查询没有同时选修物理课程和体育课程的学生姓名
--     (只要选了一门的 选了两门和没有选的都不要)
# 1 先查物理和体育课程的id
# 2 再去获取所有选了物理和体育的学生数据
# 3 按照学生分组 利用聚合函数count筛选出只选了一门的学生id
# 4 依旧id获取学生姓名
-- SELECT
-- 	student.sname 
-- FROM
-- 	student 
-- WHERE
-- 	student.sid IN (
-- 	SELECT
-- 		score.student_id 
-- 	FROM
-- 		score 
-- 	WHERE
-- 		score.course_id IN ( SELECT course.cid FROM course WHERE course.cname IN ( \'物理\', \'体育\' ) ) 
-- 	GROUP BY
-- 		score.student_id 
-- 	HAVING
-- 		COUNT( score.course_id ) = 1 
-- 	);

-- 9、 查询挂科超过两门(包括两门)的学生姓名和班级
# 1 先筛选出所有分数小于60的数据
# 2 按照学生分组 对数据进行计数获取大于等于2的数据
SELECT
	class.caption,
	student.sname 
FROM
	class
	INNER JOIN student ON class.cid = student.class_id 
WHERE
	student.sid IN (
	SELECT
		score.student_id 
	FROM
		score 
	WHERE
		score.num < 60 GROUP BY score.student_id HAVING COUNT( score.course_id ) >= 2 
	);

基于Python操作MySQL(pymysql)

模块安装:pip3 install pymsql

  • 链接数据库
conn = pymysql.connect(user=None,password=None,host=None,database=None,port=None,charset=None)   # 注:charset写utf8  不要写utf-8

connect源码参数:

image-20210504083851217


  • 产生游标对象

类似于进入mysql界面后等待命令输入的游标。

# cursor = conn.cursor() # Create a new cursor to execute queries with. 默认返回元组数据类型
cursor = conn.cursor(pymysql.cursors.DictCu

以上是关于MySQL基础的主要内容,如果未能解决你的问题,请参考以下文章

linux中怎么查看mysql数据库版本

从mysql的片段中加载ListView

[Go] 通过 17 个简短代码片段,切底弄懂 channel 基础

连接MySQL出现错误:ERROR 1045 (28000): Access denied for user ‘root‘@‘localhost‘ (using password: YES)(代码片段

使用 json rereiver php mysql 在片段中填充列表视图

关于mysql驱动版本报错解决,Cause: com.mysql.jdbc.exceptions.jdbc4Unknown system variable ‘query_cache_size(代码片段