目录
- §并发编程§
- 一、线程理论
- 二、互斥锁
- 三、GIL全局解释器锁
- 四、多进程与多线程
- 五、死锁现象
- 六、信号量
- 七、event事件
- 八、进程池与线程池
- 十、协程
- §数据库§
- 一、数据库简介
- 二、MySQL数据库
- 三、MySQL基本语句
- 四、库、表、记录的操作
- 五、创建表的基本语法
- §MySQL字段类型§
- 一、整形
- 二、浮点型
- 三、字符类型
- 五、枚举与集合
- 六、日期类型
- §字段约束条件§
- 一、无符号UNSIGNED、0填充ZEROFILL
- 二、非空 not null
- 三、默认值Default
- 四、唯一值Unique
- 五、主键Primary key
- 六、自增auto_increment
- 七、外键
- §SQL语句查询关键字§
- 一、select
- 二、from
- 三、where筛选
- 四、group by 分组
- 五、having过滤
- 六、 distinct去重
- 七、查询关键字之order by 排序
- 八、limit分页
- 九、regexp正则表达式
§并发编程§
一、线程理论
1.本质
线程(英语:thread)是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务。在Unix System V及SunOS中也被称为轻量进程(lightweight processes),但轻量进程更多指内核线程(kernel thread),而把用户线程(user thread)称为线程
进程:进程其实是资源单位,表示一块内存空间,进程负责给内部的线程提供相应的资源
线程:线程才是执行单位,表示真正的代码指令,线程负责执行真正的功能
2.特点
1.线程是独立调度和分派的基本单位。
2.同一进程中的多条线程将共享该进程中的全部系统资源。
3.一个进程可以有很多线程,每条线程并行执行不同的任务。
4.一个进程至少含有一个线程
3.创建线程的两种方式
创建进程的前提:1.重新申请一块内存空间 ;2.将所需的资源全部导入
创建线程的前提:不需要和进程一样,所以说开设线程消耗的资源远远小于开设进程
(1)Thread产生线程对象
from threading import Thread
from multiprocessing import Process
import time
def task(name):
print(f'{name} is running')
time.sleep(0.1)
print(f'{name} is over')
if __name__ == '__main__':
start_time = time.time()
# p_list = []
# for i in range(100):
# p = Process(target=task, args=('用户%s' % i,)) # 创建进程
# p.start()
# p_list.append(p)
# for p in p_list:
# p.join()
# print(time.time() - start_time) # 0.7946369647979736
t_list = []
for i in range(100):
t = Thread(target=task, args=('用户%s' % i,)) # 创建线程
t.start()
t_list.append(t)
for t in t_list:
t.join()
print(time.time() - start_time) # 0.10670590400695801
t = Thread(target=task, args=('jason',))
t.start()
print('主线程')
多进程的速度比多线程慢很多,也就是说对于计算机来说,创建进程的资源消耗比线程大的多。
(2)继承Thread类创建线程
class MyThread(Thread):
def run(self):
print('run is running')
time.sleep(1)
print('run is over')
obj = MyThread()
obj.start()
print('主线程')
4.线程对象的其他方法
方法 | 作用 |
---|---|
join() |
让主线程在子线程结束后在运行 |
active_count | 统计当前正在活跃的线程数 |
current_thread | 查看主线程名字 |
5.同进程内多个线程数据共享
在同一个进程中的多个线程数据是可以共享的
二、互斥锁
1.互斥锁的作用
互斥锁就可以实现将并发变成串行的效果,互斥锁对共享数据进行锁定,保证同一时刻只能有一个线程/进程去操作
2.互斥锁lock
from threading import Thread, Lock
from multiprocessing import Lock
import time
num = 101
# 修改数值
def test(mutex):
# 局部修改全局
global num
# 上锁(一次只有一个人可以通过)
mutex.acquire()
# 先获取num的数值
tmp = num
# 模拟延迟效果
time.sleep(0.1)
# 定义的变量数据 - 循环访问数量
tmp -= 1
num = tmp
# 释放锁
mutex.release()
# 定义空字典
t_list = []
# 创建 互斥锁
mutex = Lock()
# 循环1-100
for i in range(100):
# 创建子线程
t = Thread(target=test, args=(mutex,))
# 执行子线程
t.start()
# 将执行子线程 添加到空列表
t_list.append(t)
# 确保所有的子线程全部结束
for t in t_list:
# 串行 先执行子线程 再执行主线程
t.join()
print(num)
三、GIL全局解释器锁
GIL本质就是一把互斥锁,是夹在解释器身上的,同一个进程内的所有线程都需要先抢到GIL锁,才能执行解释器代码
1.python官方文档对GIL的解释
In CPython, the global interpreter lock, or GIL, is a mutex that prevents multiple native threads from executing Python bytecodes at once. This lock is necessary mainly because CPython’s memory management is not thread-safe. (However, since the GIL exists, other features have grown to depend on the guarantees that it enforces.
在CPython中,全局解释器锁(GIL)是一个互斥锁,它可以防止多个本地线程同时执行Python字节码。这个锁是必要的,主要是因为CPython的内存管理不是线程安全的。(然而,自从GIL存在以来,其他特性已经依赖于它强制执行的保证。)
2.GIL的优缺点
优点:保证Cpython解释器内存管理的线程安全
缺点:同一个进程内所有的线程同一时刻只能有一个执行,也就是说Cpython解释器的多线程无法实现并行,无法取得多核优势
3.GIL与Lock
GIL锁:保护的是解释器级别的数据
Lock锁:保护的是用户自己的数据
四、多进程与多线程
1.多进程与多线程的应用
多线程用于IO密集型,如socket,爬虫,web
多进程用于计算密集型,如金融分析
2.io密集型与计算密集型、多进程与多线程
单个CPU | 多个CPU | |
---|---|---|
IO密集型 | 多线程有优势 | 多线程有优势 |
计算密集型 | 多线程有优势 | 多进程有优势 |
总结:
计算密集型使用多进程
IO密集型使用多线程
五、死锁现象
是指两个或两个以上的进程或线程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将无法推进下去。此时称系统处于死锁状态或系统产生了死锁,这些永远在互相等待的进程称为死锁进程
六、信号量
在python并发编程中信号量相当于多把互斥锁
信号量:Semaphore
from threading import Thread, Lock, Semaphore
import time
import random
sp = Semaphore(5) # 可以看作一次性产生了5把互斥锁
class MyThread(Thread):
def run(self):
sp.acquire()
print(self.name)
time.sleep(random.randint(1, 3))
sp.release()
for i in range(10):
t = MyThread()
t.start()
七、event事件
事件和触发器类似,都是在某些事情发生的时候启动,也就是在某些条件下自动触发
from threading import Thread, Event
import time
event = Event() # 类似于造了一个红绿灯
def light():
print('红灯亮着的 所有人都不能动')
time.sleep(3)
print('绿灯亮了 油门踩到底 给我冲!!!')
event.set()
def car(name):
print('%s正在等红灯' % name)
event.wait()
print('%s加油门 飙车了' % name)
t = Thread(target=light)
t.start()
for i in range(5):
t = Thread(target=car, args=('熊猫PRO%s' % i,))
t.start()
八、进程池与线程池
1.池的概念
在保证计算机硬件不奔溃的前提下开设多进程和多线程,降低了程序的运行效率但是保证了计算机硬件的安全,池的功能是限制启动的进程数或线程数。
进程池:提前创建好固定数量的进程供后续程序的调用,超出则等待
线程池:提前创建好固定数量的线程供后续程序的调用,超出则等待
2.池的使用环境
当并发的任务数远远超过了计算机的承受能力时,即无法一次性开启过多的进程数或线程数时,就应该用池的概念将开启的进程数或线程数限制在计算机可承受的范围内
from concurrent.futures import ProcessPoolExecutor, ThreadPoolExecutor
import os
import time
import random
from threading import current_thread
# 1.产生含有固定数量线程的线程池
# pool = ThreadPoolExecutor(10)
pool = ProcessPoolExecutor(5)
def task(n):
print('task is running')
time.sleep(random.randint(1, 3))
print('task is over', n, current_thread().name)
print('task is over', os.getpid())
return '我是task函数的返回值'
def func(*args, **kwargs):
print('from func')
if __name__ == '__main__':
# 2.将任务提交给线程池即可
for i in range(20):
res = pool.submit(task, 123) # 朝线程池提交任务
print(res.result()) # 不能直接获取
pool.submit(task, 123).add_done_callback(func) # 反馈机制,自动将结果返回
十、协程
1.如何理解协程
进程:可以看作是资源单位
线程:可以看作是执行单位
协程:可以在单线程下实现并发,特点是将程序的效率提高
2.协程的作用
实际做法:
在代码层面欺骗CPU 让CPU觉得我们的代码里面没有IO操作,实际上IO操作被我们自己写的代码检测,一旦有检测到有IO操作,立刻让代码执行别的代码,欺骗CPU
核心:编写代码完成多道的-->切换+保存状态*
3.协程代码实现检测IO操作
import time
from gevent import monkey;
monkey.patch_all() # 固定编写 用于检测所有的IO操作(猴子补丁)
from gevent import spawn
def func1():
print('func1 running')
time.sleep(3)
print('func1 over')
def func2():
print('func2 running')
time.sleep(5)
print('func2 over')
if __name__ == '__main__':
start_time = time.time()
# func1()
# func2()
s1 = spawn(func1) # 检测代码 一旦有IO自动切换(执行没有io的操作 变向的等待io结束)
s2 = spawn(func2)
s1.join()
s2.join()
print(time.time() - start_time)
4.协程实现并发
import socket
from gevent import monkey;monkey.patch_all() # 固定编写 用于检测所有的IO操作(猴子补丁)
from gevent import spawn
def communication(sock):
while True:
data = sock.recv(1024)
print(data.decode('utf8'))
sock.send(data.upper())
def get_server():
server = socket.socket()
server.bind(('127.0.0.1', 8080))
server.listen(5)
while True:
sock, addr = server.accept() # IO操作
spawn(communication, sock)
s1 = spawn(get_server)
s1.join()
§数据库§
一、数据库简介
1.什么是数据库?
DataBase,简称DB)数据库即存放数据的仓库
,只不过这个仓库是在计算机存储设备上,而且数据是按一定的格式存放
的。
数据库是长期存放在计算机内、有组织、可共享的数据集合。
数据库中的数据按一定的数据模型组织、描述和储存,具有较小的冗余度、较高的数据独立性和易扩展性,并可为各种 用户共享
早期的时候由于没有操作系统,数据都是放在一些外部存储设备中,如磁带,纸片等,一个程序对应一个数据集,由人工进行管理,效率十分低下。
现在数据量庞大,已经不再适用。
2.什么是数据库管理系统?
(DataBase Management System 简称DBMS)
在了解了Data与DB的概念后,如何科学地组织和存储数据,如何高效获取和维护数据成了关键
这就用到了一个系统软件 --- 数据库管理系统
如MySQL、Oracle、SQLite、Access、MS SQL Server
mysql主要用于大型门户,例如搜狗、新浪等,它主要的优势就是开放源代码,因为开放源代码这个数据库是免费的,他现在是甲骨文公司的产品
。
oracle主要用于银行、铁路、飞机场等。该数据库功能强大,软件费用高。也是甲骨文公司的产品。
sql server是微软公司的产品,主要应用于大中型企业,如联想、方正等。
数据库管理员 DBA
(Database Administrator)
3.数据库管理软件分类
关系型数据库做主库,做数据的持久化保存;
缓存数据库做数据的查询
① 关系型数据库
特征1:有一个固定的表结构,并且表头(表字段)应该提前就录入好了,字段名和字段类型应该提前设定好
特征2:数据之间可以建立数据库层面的关系
代表:MySQL
、Oracle
、SqlServer
、SQLite
、DB2
、Access
(SQL语句通用)
② 非关系型数据库
缓存数据库:数据存在内存中,读取速度的快,用于数据的查询。虽然缓存数据库是基于内存做数据存取,但是拥有持久化的功能
特征1:没有固定的表结构,数据库存储采用K:V键值对的形式
特征2:数据之间无法建立数据库层面的关系,需要自己编写代码建立逻辑层面的关系
代表:Redis
、memcache
、MongoDB
二、MySQL数据库
1.什么是MySQL?
MySQL是一个数据库管理软件,本质就是一个socket编写的C/S架构的软件。
2.什么是:库 - 表 - 字段 - 记录
库 —— 文件夹
表 —— 文件
字段 —— 表格的标题
记录 —— 文件中的一行内容
3.什么是 数据库管理软件?
套接字软件
任何基于网络通信的应用程序 底层用的都是socket
- 服务端
- 基于socket通信
- 收发消息
- SQL语句
- 客户端
- 基于socket通信
- 收发消息
- SQL语句
4.MySQL的存储引擎
输入 show engines
即可查询存储引擎
mysql> show engines;
(1)MyISAM
存储数据的速度快,但是不支持行锁等功能,安全性较低
MyISAM storage engine
mysql版本 5.5及之前默认的存储引擎
(2)InnoDB
支持事务、行锁、外键等操作,存储数据的速度没有MyISAM快,但是安全性较高
Supports transactions, row-level locking, and foreign keys
mysql版本 5.5之后的默认的存储引擎
(3)MEMORY
基于内存存储数据,仅用户临时表数据存取
内存中清空后,使用memory引擎的数据表中的数据就会丢失
Hash based, stored in memory, useful for temporary tables
(4)BLACKHOLE
写入数据后会立刻丢失
/dev/null storage engine (anything you write to it disappears)
(5)使用四种引擎创建数据表产生文件类型不同
存储引擎 | 表结构文件 | 表数据文件 | 表索引文件 |
---|---|---|---|
myisam | .frm |
.MYD |
.MYI |
innodb | .frm |
.ibd |
- |
MEMORY | .frm |
- | - |
BLACKHOLE | .frm |
- | - |
三、MySQL基本语句
0.基本
1.sql语句必须以分号 ; 结尾
2.sql语句编写错误: 1)直接报错 2)\c 取消执行
1.查看库、表、记录
1.查看所有的库名称
show databases
2.查看所有的表名称
use mysql 切换进入库中
show tables
3.查看所有的记录
select * from user\G
四、库、表、记录的操作
0.系统库
MySQL
在初始化后会创建一些系统库,不同的系统库有不同的用处。
初始系统库 | 主要作用 |
---|---|
information_schema |
虚拟库,不占用磁盘空间. 存储的是数据库启动后的一些参数,如用户表信息、列信息、权限信息、字符信息等 |
performance_schema |
MySQL5.5 开始新增一个数据库. 主要用于收集数据库服务器性能参数,记录处理查询请求时发生的各种事件、锁等现象 |
mysql |
授权库,主要存储系统用户 的权限信息 |
test |
MySQL 数据库系统自动创建 的测试数据库(看下载的是不是有测试套件的版本) |
1.基于库的增删改查
不要对mysql自带的库进行操作
1.增
命名规则
可以由字母
、数字
、下划线
、@
、#
、$
,区分大小写,具有唯一性,不能使用关键字,不能单独使用数字,最长128位
创建数据库
create database db1;
创建数据库
并指定字符编码
create database db1 charset utf8mb4;
2.查
查看所有
数据库
show databases;
查看当前
数据库
select database();
查看创建的数据库
和 创建命令
show create database db1;
3.改
修改数据库的字符编码
alter database db1 character gbk;
4.删
删除数据库
drop database db1;
为了防止删除不存在的数据库报错
可以使用if
判断要执行删除的数据库是否存在
drop database if exists db1;
2.基于表的增删改查
在操作表的时候,需要指定表所在的库
0.创建表的注意点
完整语法
创建数据表其实大有讲究,它包括表名称,表字段,存储引擎,主外键类型,约束性条件,字符编码等。
如果InnoDB
数据表没有创建主键,那么MySQL
会自动创建一个以行号为准的隐藏主键。
create table 表名(
字段名1 类型(宽度) 约束条件1,
字段名2 类型(宽度) 约束条件2,
字段名3 类型(宽度) 约束条件3
)
创建表,也可以不选择数据库,使用绝对路径
create table 表名(
字段名(列名) 字段类型(数字) 约束条件,
字段名(列名) 字段类型(数字) 约束条件,
字段名(列名) 字段类型(数字) 约束条件
)default charset=utf8;
1.字段名和字段类型是必须的
2.数字和约束条件是可选的
3.约束条件也可以写多个,空格隔开即可
4.最后一行结尾不能加逗号
注意点:
1.在同一张表中 字段名不能重复
2.宽度
和 约束条件
是可选的(可写可不写)而字段名
和 字段类型
是必须的
3.约束条件写的话 也支持写多个
:
字段名 类型(宽度) 约束条件1 约束条件2 ......,
create table t1(id); # 报错
create table t1(id int);
4.最后一行
不能有逗号,不然会报错:
create table t1(
id int,
name char(8),
); # 报错
1.增
先切换数据库
,再建表
use db1;
create table t1(id int, name char);
用绝对路径
建表
create db1.t1(id int, name char);
2.查
查看当前数据库
下的所有表
show tables
查看单个表
:
show create table t1
绝对路径
查看单个表
show create db1.t1
查看表结构的详情信息
desc t1;
describe t1;
3.改
修改表中的字段的类型
modify只能修改字段类型
,不能修改其他信息
alter tabl1 t1 modify name char(10);
修改表名
alter table t1 rename tt1;
修改字段
alter table t1 modify id tinyint;
alter table t1 change id ID tinyint;
alter table t1 change id ID tinyint, change name NAME char(4);
4.删
删除表
drop table db1.t1;
drop table t1;
删除字段
alter table t1 drop name;
5.清空表数据
将表中所有记录清空,并将部分结构进行重置(如自增字段会恢复至初始值)
truncate 表名;
也可以使用delete
来清空表中数据,但是效率极低,并且无法将结构进行重置(例如:主键)
6.复制
复制表
create table t2 select user,host,password from mysql.user;
只复制表结构
,不复制表数据
create table t2 select user,host,password from mysql.user where 1!=1;
虚拟表
表本身是不存在的,硬盘中只存在一堆数据,只有在查询的时候,select语句才会拼出一张表,数据从硬盘拿到内存
3.基于记录的增删改查
1.增
增加多个字段
ALTER TABLE 表名
ADD 字段名 数据类型 [完整性约束条件…],
ADD 字段名 数据类型 [完整性约束条件…];
alter table t1 add hobby varchar(20),add home varchar(50);
增加字段 - 插入到最后
ALTER TABLE 表名
ADD 字段名 数据类型 [完整性约束条件…];
alter table t1 add gender char(4);
增加字段 - 插入到第一个
ALTER TABLE 表名
ADD 字段名 数据类型 [完整性约束条件…] FIRST;
alter table t1 add gender char(4) first;
增加字段 - 插入到指定字段
(ID)后
ALTER TABLE 表名
ADD 字段名 数据类型 [完整性约束条件…] AFTER 字段名;
alter table t1 add level int after ID;
2.改
修改字段分为修改字段名
或者修改其数据类型
modify
只能修改数据类型及其完整性约束条件
ALTER TABLE 表名
MODIFY 字段名 数据类型 [完整性约束条件…];
change
能修改字段名、数据类型及其完整性约束条件
ALTER TABLE 表名
CHANGE 旧字段名 新字段名 旧数据类型 [完整性约束条件…];
ALTER TABLE 表名
CHANGE 旧字段名 新字段名 新数据类型 [完整性约束条件…];
修改id
字段为自增主键,并将其名字修改为stu_id
alter table students change id stu_id mediumint not null primary key auto_increment first;
如果不修改名字只修改其原本的类型或完整性约束条件,可使用modify
进行操作。
3.删
删除表中的某个字段
ALTER TABLE 表名 DROP 字段名;
4.其余修改
将数据表students
存储引擎修改为memory
alter table students engine='memory';
将数据表students
字符编码修改为gbk
alter table students charset="gbk";
五、创建表的基本语法
表的完整语法
create table 表名(
字段名(列名) 字段类型(数字) 约束条件,
字段名(列名) 字段类型(数字) 约束条件,
字段名(列名) 字段类型(数字) 约束条件
)default charset=utf8;
1.字段名和字段类型是必须的
2.数字和约束条件是可选的
3.约束条件也可以写多个,空格隔开即可
4.最后一行结尾不能加逗号
§MySQL字段类型§
一、整形
整数类型 | 字节 |
---|---|
tinyint |
1 bytes = 8 bit |
smallint |
2 bytes |
int |
4 bytes |
bigint |
8 bytes |
二、浮点型
(1)FLOAT[(M,D)] [UNSIGNED] [ZEROFILL]
单精度浮点数,非准确小数值,m是数字总个数,d是小数点后个数。
(2)DOUBLE[(M,D)] [UNSIGNED] [ZEROFILL]
单精度浮点数,非准确小数值,m是数字总个数,d是小数点后个数。
(3)decimal[(M,D)] [UNSIGNED] [ZEROFILL]
双精度浮点数(非准确小数值),m是数字总个数,d是小数点后个数。
例子:三者的核心区别在精确度不同
float < double < decimal
-
正常业务使用float就可以了
-
高精度数据,可以使用decimal
# 创建三种不同浮点型的表
create table t7(id float(50,20));
create table t8(id double(50,20));
create table t9(id decimal(50,20));
# 插入数据
insert into t1 values(2.01234567890123456789);
insert into t2 values(2.01234567890123456789);
insert into t3 values(2.01234567890123456789);
----保存结果---
2.01234579086303700000
2.01234567890123460000
2.01234567890123456789
三、字符类型
(1)char(m)
-
一般适用于:固定长度的内容
-
定长字符串,m代表字符串的长度,最多可容纳255个字符。
注意:默认底层存储是固定的长度(不够则用空格补齐),但是查询数据时,会自动将空白去除。
(2)varchar(m)
-
变长字符串,m代表字符串的长度,最多可容纳65535个字节。
-
变长的体现:内容小于m时,会按照真实数据长度存储;如果超出m长度限制(默认MySQL是严格模式,所以会报错)。
(2)char
与varchat
对比
对比 | char | varchar |
---|---|---|
优势 | 整存整取 速度快 | 节省存储空间 |
劣势 | 浪费存储空间 | 存取数据的速度较char慢 |
五、枚举与集合
(1)枚举:enum()
多选一
通过enum()
来在多个选择中选1个输入,不符合则报错
create table tb2(
id int,
name varchar(16),
email varchat(32),
gender enum('male','female','others')
);
(2)集合:多选多
通过set()
来在多个选择中选择可以选多个
create table tb2(
id int,
name varchar(16),
email varchat(32),
hobby set('drink','movie','chat')
);
六、日期类型
日期类型 | 表示 |
---|---|
datetime | 年月日时分秒 |
date | 年月日 |
time | 时分秒 |
year | 年 |
§字段约束条件§
类型 | 作用 |
---|---|
PRIMARY KEY (PK) | 标识该字段为该表的主键 |
FOREIGN KEY (FK) | 标识该字段为该表的外键 |
NOT NULL | 标识该字段不能为空 |
UNIQUE KEY (UK) | 标识该字段的值是唯一 的 |
AUTO_INCREMENT | 标识该字段的值自动增长 (整数类型,而且为主键) |
DEFAULT | 为该字段设置默认值 |
UNSIGNED | 无符号 |
ZEROFILL | 使用0填充 |
一、无符号UNSIGNED、0填充ZEROFILL
unsigned 表示无符号
id int unsigned
zerofill 仅用于显示,当不满足5位时,按照左边补0,例如:00002;满足时,正常显示。
id int(5) zerofill
二、非空 not null
not null
代表该字段不能为空,必须为该字段插入值,如果不插入值则会使用默认值,如果默认值为null
则报错
(1)所有的字段类型,在不加约束条件的情况下默认都可以为空
(2)not null非空
三、默认值Default
默认值用于在创建表时为字段设置默认值,当插入时可以省略该字段的数据插入而去使用设定的默认值,如不设定默认值则为null
# 建表
create table t3(
id int default 333, -- 不填数据的情况下默认为 333
name varchar(16) default '铎铎' -- 不填数据的情况下默认为'铎铎'
);
insert into t3 values(2,null)
四、唯一值Unique
(1)单列唯一
单列唯一是指该字段下的值不能重复
# 建表
create table t4(
id int,
name varchar(32) unique -- name的值唯一不能重复
);
(2)联合唯一
联合唯一:field字段对应的值之间的组合不能重复
# 建表
create table t5(
id int,
ip varchar(32), -- 字符括号内填写的数字最好为16的倍数,并不要超过255
port varchar(32),
unique(ip,port) -- 指定ip和port的组合不能重复
);
五、主键Primary key
1.主键的特点
1)主键单从约束条件层面上而言主键相当于not nul
l + unque
==>> 非空且唯一
2)InnoDB存储引擎规定了所有的表都必须有且只有一个主键,InnoDB会根据主键锁约束字段的值来建立索引,建立表的整体结构,加速查询
2.InnoDB引擎中主键的特性
1)当表中没有显式的设置主键,InnoDB`会采用一个隐藏的字段作为表的主键
2)当表中没有主键但是有其他非空且唯一的字段,那么会从上往下讲第一个非空且唯一的该字段自动升级为主键
# 建表
create table t7(
id int,
age int not null unique,
level int not null unique,
phonenum bigint not null unique
);
3.联合主键
primary key(field1,field2,...)
uid int,
sid int,
primary key(uid,sid)
六、自增auto_increment
1.自增特点:
1)该约束条件不能单独出现,并且一张表中只能出现一次,自增主要就是配合主键一起用
2)自增字段的记录不会因为数据的删除而回退,永远自增往前
# 建表
create table t8(
id int primary key auto_increment,
name varchar(32)
);
七、外键
1.表与表之间的关系
1)一对多
如果判断的结果是一边可以一遍不可以,那么就是一对多
外键字段建在多的一方
# 建立员工表
create table emp(
id int primary key auto_increment,
name varchar(32),
age int
dep_id int,
foreign key(dep_id) references dep(id) --
);
# 建立部门表
create table dep(
id int primary key auto_increment,
dep_name varchar(32),
dep_desc varchar(32)
);
2)多对多
如果判断的结果是两边都可以,那么就是多对多
需要第三张表专门存储关系
# 创建电影表
create table film(
id int primary key auto_increment,
name varchar(64)
);
# 创建导演表
create table director(
id int primary key auto_increment,
name varchar(64)
);
# 将外键创立成表FilmTODirect
create table filmtodirect(
id int primary key auto_increment,
file_id int,
foreign key(file_id) references film(id)
on update cascade
on delete cascade,
director_id int,
foreign key(director_id) references director(id)
on update cascade
on delete cascade
);
3)一对一
如果判断的结果是两边都不可以,那么就是一对一或者没有关系
外键在哪一方都可以,但是建议建在查询频率较高的表中
# 创建用户表表
create table customer(
id int primary key auto_increment,
name varchar(20)
);
# 创建用户详情表
create table detail(
id int primary key auto_increment,
gender varchar(10),
phone varchar(11),
c_id int,
foreign key(c_id) references customer(id)
on delete cascade
on update cascade
);
§SQL语句查询关键字§
优先级 | 关键字 | 作用 |
---|---|---|
1 | from | 指定要查询的表信息 |
2 | where | 规定查询条件,然后查询并筛选 |
3 | group by | 根据指定字段进行分组,如果没有指定字段,则整个表为一组 |
4 | having | 指定查询的条件,筛选数据(二次筛选用在where之后) |
5 | select | 指定要查询的信息 |
6 | distinct | 将数据去重 |
7 | order by | 对查询的结果进行排序 |
8 | limit | 限制查询结果展示的数量 |
一、select
指定要查询的信息
select * 查找所有字段
select name 查找name字段
select char_length(name) 支持对字段做处理
二、from
指定要查询的表信息
from mysql.user
from t1
三、where筛选
where+条件可以筛选出我们想要的数据
# 查询id>=3的数据
select * from emp where id>=3;
# 查询年纪 大于40 以及 小于20的员工
select * from emp where age>40 or age<20;
-- 支持成员运算 in
select * from emp where salary in (20000,18000,17000);
-- 支持逻辑运算符 between
select * from emp where salary between 999 and 3001;
-- 支持模糊匹配,一个下划线表示一个字符
select * from emp where name like '__';
-- 通过is判断
select * from emp where post_comment is NULL; -- 可以
四、group by 分组
根据指定字段进行分组,如果没有指定字段,则整个表为一组
# 分组之后 select 后面默认只能填写分组的依据 ,不能再写其他字符段
select post from emp group by post; -- 在select后面要写分组的字段名
-- 配合聚合函数使用
# max获取得最高工资
select post,max(salary) from emp group by post;
# 获取每个部门最小的年龄
select post,min(age) from emp group by post;
-- 起别名减少资源使用
select post as '部门',max(salary) as '最高薪资' from emp group by post;
-- count计数
select post,count(id) from emp group by post;
-- group_concat()分组之后其他字段的筛选与拼接
select post,group_concat(name) from emp group by post;
五、having过滤
指定查询的条件,筛选数据(二次筛选用在where之后)
1.having和where的区别异同点
相同:having 与 where 本质是一样的,都是用来对数据做筛选
不同: where用在分组之前(首次筛选)
having用在分组之后(二次筛选)
# having二次筛选
select age,avg(salary) as avg_salary -- 起别名
from emp
where id>15 -- 第一次筛选
group by age
having avg_salary >10000; -- 二次筛选
六、 distinct去重
distinct用于数据去重,存在数据必须一模一样才可以去重
# 去重 age和salary的组合
select distinct age,salary from emp;
七、查询关键字之order by 排序
ordery by
用于对查询结果进行排序,默认的排序是按照主键
进行排序的
1.单个字段排序
# 默认升序
select * from emp order by age;
-- 默认尾部填写 asc 升序
# desc可以改成降序
select * from emp order by age desc;
2.多个字段排序
# 多个字段排序
select post,avg(salary) from emp where age >10 group by post having avg(salary)>1000 order by avg(salary);
# 用as 起别名,节省调用次数,也就是节省了底层运行效率
select post,avg(salary) as asg from emp where age >10 group by post having asg>1000 order by asg;
八、limit分页
limit
用于控制显示的条数
# limit num 直接限制展示的条数
select * from emp limit 3
# limit num1,num2`限制展示范围
select * from emp limit 3,6
九、regexp正则表达式
SQL语句的模糊匹配如果用不习惯 也可以自己写正则批量查询
select * from emp where name regexp '^j.';
标签:name,数据库,11.27,周末,线程,MySQL,table,create,id
From: https://www.cnblogs.com/DuoDuosg/p/16930327.html