首页 > 其他分享 >本周内容总结

本周内容总结

时间:2022-11-27 18:45:11浏览次数:30  
标签:总结 name int 本周 内容 mysql 线程 id select

互斥锁、死锁、信号量、线程、协程

目录

互斥锁

互斥锁对共享数据进行锁定,保证同一时刻只能有一个线程去操作。
ps:互斥锁是多个线程一起去抢,抢到锁的线程先执行,没有抢到锁的线程需要等待,等互斥锁使用完释放后,其他等待的线程再去抢这个锁。

互斥锁代码实操

threading模块中定义了Lock变量,这个变量本质上是一个函数,通过调用这个函数可以获取一把互斥锁。
import threading

g_num = 0
lock = threading.Lock()  # 循环100万次执行的任务


def task():
    lock.acquire()  # 上锁
    for i in range(2000000):
        global g_num  # 声明修改全局变量的内存地址
        g_num = g_num + 1
    print("task1", g_num)
    lock.release()  # 释放锁


def task2():
    lock.acquire()  # 上锁
    for i in range(1000000):
        global g_num  # 声明修改全局变量的内存地址
        g_num = g_num + 1
    print("task2", g_num)
    lock.release()  # 释放锁


if __name__ == '__main__':
    first_threat = threading.Thread(target=task)
    second_threat = threading.Thread(target=task2)
    first_threat.start()
    second_threat.start()
#输出结果
task1 2000000
task2 3000000

#互斥锁可以保证同意时刻只有一个线程会执行代码,能够保证全局变量的数据没有问题
#线程等待把互斥锁都是把多任务改成单任务去执行,保证了数据的准确性,但是执行性能会下降

ps:
    acquire和release方法之间的代码同一时刻只能有一个线程去操作。
    如果在调用acquire方法的时候,其他线程已经使用了这个互斥锁,那么此时acquire方法会堵塞,直到这个互斥锁释放后才能再次上锁。

总结:
	互斥锁的作用就是保证同一时刻只能有一个线程去操作共享数据,保证共享数据不会出现错误问题
    使用互斥锁的好处确保某段关键代码只能由一个线程从头到尾完整的去执行
    使用互斥锁会影响代码的执行效率,多任务改成了单任务执行
    互斥锁如果没有使用好容易出现死锁的情况

线程理论

线程是CPU的基本执行单位,里面包括真正要执行的代码
进程是一个资源单位,其中包括了这个程序需要的所有资源
类比的话,进程就像是一个工厂,里面包括了生产所需所有资源;线程像一条流水线,包含具体的执行步骤。
一个工厂可以包括多个线程,每个线程可以生产不同的产品。每个线程被启动后会自动创建一个线程,该线程会从程序入口开始执行代码(py程序入口就是被执行文件的第一行)被称之为主线程。
如果主线程在完成任务时耗时过长,可以开启子线程来辅助主线程。
from threading import Thread

a = 100


def task():
    global a
    a = 1
    print("这是给子线程执行的任务")


# 创建一个子线程
t = Thread(target=task)
# 启动这个子线程
t.start()
print("主")
print(a)

# 在多进程中,开启子进程需要消耗大量的资源,所以主进程会先比子进程执行
# 子线程的开启速度比进程快的多
# 在多线程中,子线程可以直接访问主线程的内容
# 多个线程之间是平等的,所以不存在父子关系
# 在今后的开发中,每当出现i/o阻塞 ,比较耗时的操作

import time, os


def task():
    time.sleep(2)
    print("子线程 run......")
    print(os.getpid())


t = Thread(target=task)
t.start()
# 主线程等到子线程结束
t.join()
print("over")
print(os.getpid())

创建线程的两种方式

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)
    # 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)

# t = Thread(target=task, args=('jason',))
# t.start()
# print('主线程')
"""
创建线程无需考虑反复执行的问题
"""


class MyThread(Thread):
    def run(self):
        print('run is running')
        time.sleep(1)
        print('run is over')

obj = MyThread()
obj.start()
print('主线程')

线程的诸多特性

  • join方法
  • 同进程内多个线程数据共享
  • current_thread()
  • active_count()

GIL全局解释器锁

# 官方文档对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存在以来,其他特性已经依赖于它强制执行的保证。)

"""
1.在CPython解释器中存在全局解释器锁简称GIL
	python解释器有很多类型
	CPython JPython PyPython (常用的是CPython解释器)
2.GIL本质也是一把互斥锁 用来阻止同一个进程内多个线程同时执行(重要)
3.GIL的存在是因为CPython解释器中内存管理不是线程安全的(垃圾回收机制)
	垃圾回收机制
		引用计数、标记清除、分代回收
"""

验证GIL的存在

from threading import Thread

num = 100


def task():
    global num
    num -= 1


t_list = []
for i in range(100):
    t = Thread(target=task)
    t.start()
    t_list.append(t)
for t in t_list:
    t.join()
print(num)
# 0

GIL与普通互斥锁

GIL只能够确保同进程内多线程数据不会被垃圾回收机制弄乱,并不能确保程序里面的数据是否安全。
import time
from threading import Thread, Lock

num = 100


def task(mutex):
    global num
    mutex.acquire()
    count = num
    time.sleep(0.1)
    num = count - 1
    mutex.release()


mutex = Lock()
t_list = []
for i in range(100):
    t = Thread(target=task, args=(mutex,))
    t.start()
    t_list.append(t)
for t in t_list:
    t.join()
print(num)
# 0

python多线程是否有用

首先分情况:情况1,单个CPU/多个CPU;情况2,IO密集型(代码有IO操作)/计算密集型(代码没有IO)
1.单个CPU
IO密集型:
多进程:申请额外空间,消耗更多的资源;
多线程:消耗资源相对较少,通过多道技术
#多线程有优势

计算密集型:
多进程:申请额外的空间 消耗更多的资源(总耗时+申请空间+拷贝代码+切换)
多线程:消耗资源相对较少 通过多道技术(总耗时+切换)
#多线程有优势

2.多个CPU
IO密集型:
多进程:总耗时(单个进程的耗时+IO+申请空间+拷贝代码)
多线程:总耗时(单个进程的耗时+IO)
#多线程有优势

计算密集型:
多进程:总耗时(单个进程的耗时)
多线程:总耗时(多个进程的综合)
#多进程完胜

代码实现:
from threading import Thread
from multiprocessing import Process
import os
import time


def work():
    # 计算密集型
    res = 1
    for i in range(1, 100000):
        res *= i


if __name__ == '__main__':
    # print(os.cpu_count())  # 12  查看当前计算机CPU个数
    start_time = time.time()
    # p_list = []
    # for i in range(12):  # 一次性创建12个进程
    #     p = Process(target=work)
    #     p.start()
    #     p_list.append(p)
    # for p in p_list:  # 确保所有的进程全部运行完毕
    #     p.join()
    t_list = []
    for i in range(12):
        t = Thread(target=work)
        t.start()
        t_list.append(t)
    for t in t_list:
        t.join()
    print('总耗时:%s' % (time.time() - start_time))  # 获取总的耗时

"""
计算密集型
    多进程:5.665567398071289
    多线程:30.233906745910645
"""

def work():
    time.sleep(2)   # 模拟纯IO操作


if __name__ == '__main__':
    start_time = time.time()
    # t_list = []
    # for i in range(100):
    #     t = Thread(target=work)
    #     t.start()
    # for t in t_list:
    #     t.join()
    p_list = []
    for i in range(100):
        p = Process(target=work)
        p.start()
    for p in p_list:
        p.join()
    print('总耗时:%s' % (time.time() - start_time))

"""
IO密集型
    多线程:0.0149583816528320
    多进程:0.6402878761291504
"""

死锁现象

	两个或两个以上的进程或线程在执行过程中,因抢夺资源而造成的一种互相等待的现象,若无外力作用,它们都将无法推进下去。此时称系统处于死锁状态或系统产生了死锁,这些永远在互相等待的进程称为死锁现象。
"""
虽然我们已经掌握了互斥锁的使用
	先抢锁 后释放锁
但是在实际项目尽量少用(你也不会用!!!)
"""
from threading import Thread, Lock
import time

mutexA = Lock()  # 类名加括号每执行一次就会产生一个新的对象
mutexB = Lock()  # 类名加括号每执行一次就会产生一个新的对象
'''
Lock()是一个类,类名加括号,每执行一次就会产生一个对象
类名加括号每执行一次就会产生一个新的对象,可以用单例模式实现
'''

class MyThread(Thread):
    def run(self):
        self.func1()
        self.func2()

    def func1(self):
        mutexA.acquire()
        print(f'{self.name}抢到了A锁')
        mutexB.acquire()
        print(f'{self.name}抢到了B锁')
        mutexB.release()
        print(f'{self.name}释放了B锁')
        mutexA.release()
        print(f'{self.name}释放了A锁')

    def func2(self):
        mutexB.acquire()
        print(f'{self.name}抢到了B锁')
        time.sleep(1)
        mutexA.acquire()
        print(f'{self.name}抢到了A锁')
        mutexA.release()
        print(f'{self.name}释放了A锁')
        mutexB.release()
        print(f'{self.name}释放了B锁')


for i in range(10):
    t = MyThread()
    t.start()

信号量

互斥锁同时只允许一个线程更改数据,而Semaphore是同时允许一定数量的线程更改数据。
    Semaphore管理一个内置的计数器,
    每当调用acquire()时内置计数器-1;
    调用release() 时内置计数器+1;
    计数器不能小于0;当计数器为0时,acquire()将阻塞线程直到其他线程调用release()
锁信号量与进程池的概念很像,但是要区分开,信号量涉及到加锁的概念。
信号量本质也是互斥锁 只不过它是多把锁
强调:
    信号量在不同的知识体系中,意思可能有区别
        在并发编程中,信号量就是多把互斥锁
        在django中,信号量指的是达到某个条件自动触发(中间件)
        ...
我们之前使用Lock产生的是单把锁
	类似于单间厕所
信号量相当于一次性创建多间厕所
	类似于公共厕所
    

from threading import Thread, Lock, Semaphore
import time
import random

sp = Semaphore(5)  # 一次性产生五把锁

class MyThread(Thread):
    def run(self):
        sp.acquire()
        print(self.name)
        time.sleep(random.randint(1, 3))
        sp.release()

for i in range(20):
    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)


if __name__ == '__main__':
    t = Thread(target=light)
    t.start()

    for i in range(20):
        t = Thread(target=car, args=('%s'%i, ))
        t.start()

进程池与线程池

先回顾之前TCP服务端实现并发的效果是怎么玩的
每来一个人就开设一个进程或者线程去处理
"""
无论是开设进程也好还是开设线程也好 是不是都需要消耗资源
只不过开设线程的消耗比开设进程的稍微小一点而已

我们是不可能做到无限制的开设进程和线程的 因为计算机硬件的资源更不上!!!
硬件的开发速度远远赶不上软件呐

我们的宗旨应该是在保证计算机硬件能够正常工作的情况下最大限度的利用它
"""
# 池的概念
"""
什么是池?
	池是用来保证计算机硬件安全的情况下最大限度的利用计算机
	它降低了程序的运行效率但是保证了计算机硬件的安全 从而让你写的程序能够正常运行
"""

from concurrent.futures import ThreadPoolExecutor, ProcessPoolExecutor
import time
import os


# pool = ThreadPoolExecutor(5)  # 池子里面固定只有五个线程
# 括号内可以传数字 不传的话默认会开设当前计算机cpu个数五倍的线程
pool = ProcessPoolExecutor(5)
# 括号内可以传数字 不传的话默认会开设当前计算机cpu个数进程
"""
池子造出来之后 里面会固定存在五个线程
这个五个线程不会出现重复创建和销毁的过程
池子造出来之后 里面会固定的几个进程
这个几个进程不会出现重复创建和销毁的过程

池子的使用非常的简单
你只需要将需要做的任务往池子中提交即可 自动会有人来服务你
"""


def task(n):
    print(n,os.getpid())
    time.sleep(2)
    return n**n

def call_back(n):
    print('call_back>>>:',n.result())
"""
任务的提交方式
    同步:提交任务之后原地等待任务的返回结果 期间不做任何事
    异步:提交任务之后不等待任务的返回结果 执行继续往下执行
        返回结果如何获取???
        异步提交任务的返回结果 应该通过回调机制来获取
        回调机制
            就相当于给每个异步任务绑定了一个定时炸弹
            一旦该任务有结果立刻触发爆炸
"""
if __name__ == '__main__':
    # pool.submit(task, 1)  # 朝池子中提交任务  异步提交
    # print('主')
    t_list = []
    for i in range(20):  # 朝池子中提交20个任务
        # res = pool.submit(task, i)  # <Future at 0x100f97b38 state=running>
        res = pool.submit(task, i).add_done_callback(call_back)
        # print(res.result())  # result方法   同步提交
        # t_list.append(res)
    # 等待线程池中所有的任务执行完毕之后再继续往下执行
    # pool.shutdown()  # 关闭线程池  等待线程池中所有的任务运行完毕
    # for t in t_list:
    #     print('>>>:',t.result())  # 肯定是有序的
"""
程序有并发变成了串行
任务的为什么打印的是None
res.result() 拿到的就是异步提交的任务的返回结果
"""

协程

"""
进程:资源单位
线程:执行单位
协程:这个概念完全是程序员自己意淫出来的 根本不存在
		单线程下实现并发
		我们程序员自己再代码层面上检测我们所有的IO操作
		一旦遇到IO了 我们在代码级别完成切换
		这样给CPU的感觉是你这个程序一直在运行 没有IO
		从而提升程序的运行效率
	
多道技术
	切换+保存状态
	CPU两种切换
		1.程序遇到IO
		2.程序长时间占用

TCP服务端 
	accept
	recv
	
代码如何做到
	切换+保存状态

切换
	切换不一定是提升效率 也有可能是降低效率
	IO切			提升
	没有IO切 降低
		
保存状态
	保存上一次我执行的状态 下一次来接着上一次的操作继续往后执行
	yield
"""

验证切换是否就一定提升效率
# import time
#
# # 串行执行计算密集型的任务   1.2372429370880127
# def func1():
#     for i in range(10000000):
#         i + 1
#
# def func2():
#     for i in range(10000000):
#         i + 1
#
# start_time = time.time()
# func1()
# func2()
# print(time.time() - start_time)

# 切换 + yield  2.1247239112854004
# import time
#
#
# def func1():
#     while True:
#         10000000 + 1
#         yield
#
#
# def func2():
#     g = func1()  # 先初始化出生成器
#     for i in range(10000000):
#         i + 1
#         next(g)
#
# start_time = time.time()
# func2()
# print(time.time() - start_time)

协程实现并发

# 服务端
from gevent import monkey;monkey.patch_all()
import socket
from gevent import spawn


def communication(conn):
    while True:
        try:
            data = conn.recv(1024)
            if len(data) == 0: break
            conn.send(data.upper())
        except ConnectionResetError as e:
            print(e)
            break
    conn.close()


def server(ip, port):
    server = socket.socket()
    server.bind((ip, port))
    server.listen(5)
    while True:
        conn, addr = server.accept()
        spawn(communication, conn)


if __name__ == '__main__':
    g1 = spawn(server, '127.0.0.1', 8080)
    g1.join()

    
# 客户端
from threading import Thread, current_thread
import socket


def x_client():
    client = socket.socket()
    client.connect(('127.0.0.1',8080))
    n = 0
    while True:
        msg = '%s say hello %s'%(current_thread().name,n)
        n += 1
        client.send(msg.encode('utf-8'))
        data = client.recv(1024)
        print(data.decode('utf-8'))


if __name__ == '__main__':
    for i in range(500):
        t = Thread(target=x_client)
        t.start()

"""
理想状态:
	我们可以通过
	多进程下面开设多线程
	多线程下面再开设协程序
	从而使我们的程序执行效率提升
"""

存取数据的演变史

1.文本文件
	文件路径不固定:C:\aaa.txt  D:\bbb.txt  E:\ccc.txt
    数据格式不统一:jason|123  jason$123  jason 123
2.软件开发目录规范
	规定了数据应该保存在db目录下>>>:路径偏向统一
        db/user.txt  db/userinfo.txt  db/jason.json  db/json
	数据格式还是没有得到统一
    	文本 json格式 对象
3.数据库服务
	统一路径,统一操作方式
    降低学习成本,提高开发效率

数据库软件应用史

1.单机模式
在不同计算机上的相同程序,数据是无法共享,因为数据库服务全部在本地完成。
2.网络游戏
在不同计算机上的相同程序,数据可以共享,因为数据库服务单独在网络架构(远程数据库服务)
"""
数据库服务集群:提升数据的安全性
"""
ps:远程数据库服务含有数据库集群,数据库集群可以解决数据安全问题、服务器负载问题,让多台服务器运行相同的数据库服务。

数据库的本质

1.站在底层原理的角度
	数据库指的是操作数据的进程(一堆代码)
2.站在实际应用的角度
	数据库指的是可视化操作界面(一些软件)
ps:以后不做特殊说明的情况下讲数据库其实指的是数据库软件
3.数据库软件本质也是CS架构的程序
	意味着所有的程序员其实都有资格编写一款数据库软件

数据库的分类

  • 数据库分为关系型数据库和非关系数据库
#关系型数据库
1.数据的组织方式有明确的表结构
eg: id name password
ps:关系型数据库存取数据的方式可以看成是表格

2.表与表之间可以建立数据层面上的关系
eg:用户表 房屋表
ps:只要获取到某一表的一条数据,就可以获取到与之相关的其他表数据

3.常用的关系型数据库:MySQL、PostgreSQL、MariaDB、Oracle、sqlite、db2、SQL、server
MySQL:是开源的,使用最为广泛的,数据库学习必须要学习的
PostgreSQL:是开源的,支持二次开发的
MariaDB:是开源的,与MySQL是同一作者,用法也极其相似
Oracle:收费,安全性极高,主要用于银行及各大重要机关
sqlite:小型数据库,主要用于本地测试(Django框架自带该数据库)

#非关系型数据库
1.数据的组织方式没有明确的表结构,是以K:V键值对的形式组织的
    eg:{'name':'jason','pwd':123}
    	{'username':'liz'}
2.数据之间无法直接建立数据库层面的关系
3.常用的非关系数据库:redis、MongoDB、memcache
	redis:目前最火的,使用频率最高的缓存型数据库
	MongoDB:稳定型数据库,最像关系型的非关系型,主要用于爬虫、大数据
	memcache:已经被redis淘汰

MySQL简介

  • MySQL版本问题

    5.6x是前几年使用频率最高的版本;

    5.7x是最近尝试迁移的版本(频率+);

    8.0x是最新版,功能强大,但是线上环境几乎不用(本地自己使用好用)

MySQL的下载与安装

1.访问官网
https://www.mysql.com/
2、点击DOWNLOADS

在这里插入图片描述

3.点击MySQL Community(GPL) Downloads

在这里插入图片描述

4.点击MySQL Community Server
在这里插入图片描述
5.点击Archives(选择版本)
在这里插入图片描述
6.点击Download

在这里插入图片描述

7.解压

将下好的压缩包解压到D盘根目录(下载的压缩包里面有服务端和客户端,支持本地操作)

MySQL主要文件介绍

1.bin文件夹
里面有mysqld.exe是服务端启动程序;mysql.exe是客户端启动程序
2.data文件夹
data文件夹是用来存取数据
3.my-default.ini
my-default.ini是默认的配置文件
4.readme
软件说明

MySQL基本使用

cmd建议使用管理员身份打开
1.先启动服务端(需要知道mysqld文件位置)
	在cmd命令提示符窗口中启动服务端,可能会报错(百度解决);启动之后不要关	 闭,此时cmd窗口就是服务端
2.再次进入cmd窗口,进入mysql的文件路路径
	直接mysql回车,会以游客的模式进入,功能很少
3.用户名密码登陆
	输入:mysql-u用户名/-p密码;
    那mysql默认管理员账号:用户名是root,密码是空
4.退出
	直接输入exit或者quit
    

系统服务的制作

1.如何解决每次都需要切换路径查找文件的缺陷
	将bin文件夹路径添加到添加环境变量(属性、高级系统设置、环境变量、系统变量里的Path、编辑、新建、输入bin文件夹路径)
2.将mysql服务端制作成系统服务(随着计算机的开启而启动,关闭而结束)
	2.1 以管理员身份打开cmd窗口
	2.2 执行系统服务命令mysqld --install
	ps:可通过查看系统服务的命令(services.msc)有没有MySQL自动运行
	2.3 启动服务端
		方式一:右键直接点击启动
		方式二:命令启动:直接输入:net start mysql
3.补充知识:
	3.1 查看系统服务的命令:services.msc
	3.2 关闭mysql服务端:net stop mysql
	3.3 移除系统服务
		3.3.1 先确保服务已经关闭
		3.3.2 执行移除命令:mysql --remove	

密码相关操作

1.修改密码
	方式1:mysqladmin 
		mysqladmin -u用户名 -p原密码 password 新密码
	方式2:直接修改存储用户数据的表
	方式3:冷门操作 有些版本可能还不支持 
       set password=password('新密码')  # 修改当前登录用户的密码
     
2.忘记密码
	方式1:卸载重新装
  	方式2:把data目录删除 拷贝同桌的目录
 	方式3:小把戏操作
		1.关闭正常的服务端
   		2.以跳过授权表的方式重启服务端(不校验密码)
    	3.以管理员身份进入然后修改mysql.user表数据即可
   			net stop mysql
          mysqld --skip-grant-table
          mysql -uroot -p
          update mysql.user set password=password('123') where Host='localhost' and User='root';
  		4.关闭服务端 然后以正常方式启动即可

SQL与NoSQL

1.数据库的服务端支持各种语言充当客户端
	eg:以MySQL服务端为例,可以有MySQL客户端python代码编写的客户端,java代码编写的客户端,为了能够兼容所有类型的客户端,有两种策略:
	1.1 服务端兼容:是不合理的,消耗数据库服务daunt资源
	1.2指定统一标准:SQL语句、Nosql语句
2.SQL与NoSQL
	SQL语句的意思是操作关系型数据库的语法
	NoSQL语句的意思是操作非关系型数据库的语法
ps:SQL有时候也用来表示关系型数据库,NoSQL也用来表示非关系型数据库
    

数据库重要概念

1.库,表示文件夹,用(show databases)查看所有数据库
2.表,表示文件夹里面的文件,用(show tables)查看所有的表
3.记录,表示文件里一行行的数据,用(select*from mysql.表名)来查看表里面所有的记录
4.SQL语句结束符是分号( ;)
5.取消SQL语句的执行 (\c)
6.查看当前所在的库名:select database();
	如果没有切换指定的库,那么默认就是none
7.切换库:use 库名;

基本SQL语句

1.sql语句必须以分号结尾
2.sql语句编写错误之后不用担心 可以直接执行报错即可

'''基于库的增删改查'''
1.创建库
	create database 库名;
2.查看库
	show databases;  #查看所有的库名称
 	show create database 库名;  #查看指定库信息
3.编辑库
	alter database 库名 charset='utf8';
4.删除库
	drop database 库名;
 
'''基于表的增删改查'''
操作表之前需要先确定库
	create database db1;
切换操作库
	use db1;
1.创建表
	create table 表名(字段名 字段类型,字段名 字段类型);
2.查看表
	show tables;  #查看库下所有的表名称
	show create table 表名;  #查看指定表信息
	describe 表名;  #查看表结构
	desc 表名;
 	"""
 	ps:如果想跨库操作其他表只需要在表名前加库名即可
        desc mysql.user;
    """
3.编辑表
	alter table 表名 rename 新表名;
4.删除表
	drop table 表名;
    
'''基于记录的增删改查'''
1.插入数据
	insert into 表名 values(数据值1,数据值2);
2.查询数据
	select * from 表名; #查询表中所有的数据
3.编辑数据
	update 表名 set 字段名=新数据 where 筛选条件;
4.删除数据
	delete from 表名;
	delete from 表名 where id=2;

字符编码与配置文件

  • 在mysql中,有时候我们在输入中文时会出现乱码的现象,这是因为编码的问题。img
  • 我们输入\s先查看数据库的基本信息(用户、字符编码),可以发现有拉丁编码和GBK编码,由于5.6版本编码不统一会造成乱码,我们需要统一修改为utf8
img
my-default.ini  #windows下mysql默认的配置文件
在此之前我们要先创建一个.ini文件,在里面添加下面的代码保存即可。

#添加字符编码相关的配置
[mysqld]
    character-set-server=utf8mb4
    collation-server=utf8mb4_general_ci
[client]
    default-character-set=utf8mb4
[mysql]
    default-character-set=utf8mb4

img
  • 重启完服务端我们再次运行\s查看编码,会发现编码已经被我们改成了utf8
img
  • 偷懒操作,在配置文件中的mysql下提前写好用户名和密码之后直接mysql登录(在my.ini中)
img

存储引擎

简单理解就是存储引擎针对相同的数据采用不同的存储策略
show engine;#查看所有的存储引擎
img

主要的四个存储引擎

MyISAM
    MySQL5.5之前默认的存储引擎
    存取数据的速度快 但是功能较少 安全性较低
InnoDB
    MySQL5.5之后默认的存储引擎
    支持事务、行锁、外键等操作 存取速度没有MyISAM快 但是安全性更高
Memory
	基于内存存取数据 仅用于临时表数据存取
BlackHole
	任何写入进去的数据都会立刻丢失

#了解不同存储引擎底层文件个数
"""ps:MySQL中默认是大小写不敏感的(忽略大小写)"""
create database db2;
use db2;
create table t1(id int) engine=innodb;
create table t2(id int) engine=myisam;
create table t3(id int) engine=memory;
create table t4(id int) engine=blackhole;
ps:windows cmd终端鼠标右键的意思就是粘贴

insert into t1 values(1);
insert into t2 values(1);
insert into t3 values(1);
insert into t4 values(1);
#t1,t2中的内容是可以永久保存的,而t3的内容是临时保存的,t4根本就不保存。

运行结束查看文件夹可以看到有这些文件:

img

InnoDB
     .frm    表结构
     .ibd    表数据、表索引(加快数据查询)
MyISAM
     .frm    表结构
     .MYD    表数据
     .MYI    表索引(加快数据查询)
Memory
      .frm    表结构
BlackHole
      .frm    表结构

创建表的完整语法

create table 表名(
	字段名 字段类型(数字) 约束条件,
	字段名 字段类型(数字) 约束条件,
 	字段名 字段类型(数字) 约束条件
);
1.字段名和字段类型是必须的
2.数字和约束条件是可选的
3.约束条件也可以写多个 空格隔开即可
4.最后一行结尾不能加逗号
ps:编写SQL语句报错之后不要慌 仔细查看提示 会很快解决 

字段类型之整型

img

验证整型默认是否携带正负号
	create table t5(id tinyint);
    insert into t5 values(-129),(128);
结果是-128和127,也就意味着默认自带正负号

自定义移除负号
  '''unsigned 约束条件之一 意思是不需要负号'''
	create table t6(id tinyint unsigned);
    insert into t6 values (-129),(128),(1000);

严格模式

当我们在使用数据库存储数据的时候,如果数据不符合规范,应该直接报错而不是擅自修改数据,这样会导致数据的失真(没有实际意义)

方式1:命令临时修改
	set session sql_mode='strict_trans_tables'
    #当前客户端操作界面有效
	set global sql_mode='STRICT_TRANS_TABLES'
    #服务端不重启永久有效

方式2:配置文件永久修改
	[mysqld]
		sql_mode='STRICT_TRANS_TABLES'

字段类型之浮点型

img

主要认识有float、double、decimal三种浮点型,三者都可以存储浮点型数据,但是各自的精确度不一致。
float(20,10)
	总共存储20位数 小数点后面占10
double(20,10)
	总共存储20位数 小数点后面占10
decimal(20,10)
	总共存储20位数 小数点后面占10
# 第一个数表示总共多少位 第二个数表示小数占多少位

验证精确度问题
create table t7(id float(60,20));
create table t8(id double(60,20));
create table t9(id decimal(60,20));
insert into t7 values(1.11111111111111111111);
insert into t8 values(1.11111111111111111111);
insert into t9 values(1.11111111111111111111);

精确度排序:  float < double < decimal
ps:
  一般情况下float足够使用了
  如果想追求非常完美的精确度,可以使用字符串来代替

字段类型之字符类型

char 定长
	char(4)  最多存储四个字符 超出就报错 不够四个空格填充至四个
varchar 变长
	varchar(4) 最多存储四个字符 超出就报错 不够则有几位存几位
#sql_mode='strict_trans_tables'  要写在配置文件中

create table t10(id int, name char(4));
create table t11(id int, name varchar(4));
insert into t10 values(1, 'jason1');
insert into t11 values(1, 'jason2');
ps:
    char_length()获取字段存储的数据长度
    默认情况下mysql针对char的存储会自动填充空格和删除空格
    如果想取消该机制需要sql_mode set global
set global sql_mode='strict_trans_tables,pad_char_to_full_length';
上述目录是替换 不是新增 所以之前的配置也要写上

char VS varchar
    char
        优势:整存整取 速度快
        劣势:浪费存储空间
	 varchar
		优势:节省存储空间 
		劣势:存取数据的速度较char慢
"""
     char(4)
         a son jacktom lili
     varchar(4)
         1bytes+a1bytes+son1bytes+jack1bytes+tom1bytes+lili
         存取数据都需要操作报头(耗时)
     
     存储人的姓名>>>:varchar
     """
# char与varchar的使用需要结合具体应用场景,两者使用频率都很高,现在默认很多时候是varchar

数字的含义

数字在很多地方都是用来表示限制存储数据的长度 
	但是在整型中数字却不是用来限制存储长度
create table t12(id int(3)); 不是用来限制长度
insert into t12 values(12345);

create table t13(id int(5) zerofill);  而是用来控制展示的长度
insert into t13 values(123),(123456789);

create table t14(id int);

"""以后写整型无需添加数字"""

字段类型之枚举与集合

枚举
	多选一
	create table t15(
    	id int,
      	name varchar(32),
       gender enum('male','female','others')
    );
 	insert into t15 values(1,'tony','猛男');
  	insert into t15 values(2,'jason','male');
 	insert into t15 values(3,'kevin','others');

集合
	多选多(多选一)
	create table t16(
    	id int,
      	name varchar(16),
       hobbies set('basketabll','football','doublecolorball')
    );
 	insert into t16 values(1,'jason','study');
 	insert into t16 values(2,'tony','doublecolorball');
	insert into t16 values(3,'kevin','doublecolorball,football');

字段类型之日期类型

datetime		年月日时分秒
date			年月日
time			时分秒
year			年

create table t17(
	id int,
  	name varchar(32),
 	register_time datetime,
 	birthday date,
 	study_time time,
 	work_time year
);
insert into t17 values(1,'jason','2000-11-11 11:11:11','1998-01-21','11:11:11','2000');
ps:以后涉及到日期相关字段一般都是系统自动回去 无需我们可以操作

字段约束条件

约束是一种限制,通过对表中的数据做出限制,来确保表中数据完整性、唯一性。
1.unsigned
	无需正负号
    eg:id int unsigned
2.zerofill
	在插入数据时,当该字段的值的长度小于定义的长度时,会在该值的前面补上相应的0
    eg:id int(5) zerofill
3.not null
	不能为空(非空)
    eg:name varchar(32)not null
    注意:空字符串不等于null
4.default
	默认值
    插入数据值时,如果没有明确为字段赋值,则自动赋予默认值,在没有默认值的情况下,默认为null

mysql> create table t1(id int, name varchar(32)default 'jason');
Query OK, 0 rows affected (0.65 sec)

mysql> insert into t1(id)values(1);
Query OK, 1 row affected (0.09 sec)

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

5.unique
	唯一值
    限制一个字段的值不重复,该字段的数据不能出现重复。确保字段中的值唯一
    eg:id int unique 单列唯一
    eg:unique(字段名,字段名) 联合唯一
    
mysql> create table t2(id int unique,name varchar(32) default 'jason');
Query OK, 0 rows affected (0.34 sec)

mysql> insert into t2(id) values(1);
Query OK, 1 row affected (0.12 sec)

mysql> insert into t2(id) values(1);
ERROR 1062 (23000): Duplicate entry '1' for key 'id'
mysql> insert into t2(id) values(2);
Query OK, 1 row affected (0.12 sec)
    

主键

关键字:primary key

定义:
	主键(primary)的完整称呼是“主键约束”。MySQL主键约束是一个列或者列的组合,其值能唯一的标识表中的每一行。这样的一列或多列称为表的主键,通过它可以强制表的实体完整性。

强调:
	在关系数据库,一个表中只能有一个主键,有些数据库没有主键,系统报错。在MySQL数据库中,建立表时,可以有主键,也可以没有(推荐建立表时必须要有主键)。

#单从约束角度上而言,主键等价于非空且唯一 not null unique
mysql> create table t3(id int primary key,name varchar(32) default'jason');
Query OK, 0 rows affected (0.59 sec)

mysql> insert into t3(name)values('jason');
ERROR 1364 (HY000): Field 'id' doesn't have a default value
mysql> insert into t3(id,name)values(1,'jason');
Query OK, 1 row affected (0.12 sec)

mysql> insert into t3(id,name)values(1,'jason');
ERROR 1062 (23000): Duplicate entry '1' for key 'PRIMARY'
mysql> insert into t3(id,name) values(2,'kevin');
Query OK, 1 row affected (0.37 sec)

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

#InnoDB存储引擎规定了所有的表都必须有且只有一个主键(主键是组织数据的重要条件并且主键可以加快数据的查询速度)
1.当表中没有主键也没有其他非空且唯一的字段的情况下
	InnoDB会采用一个隐藏的字段作为表的主键,隐藏意味着无法使用,基于该表的数据查询只能一行行查找,速度很慢。
2.当表中没有主键但是有其他非空且唯一的字段,那么会从上往下将第一个该字段自动升级为主键
mysql> create table t4(id int,age int not null unique,phone bigint not null unique,brith int not null unique,
    -> height int not null unique);
Query OK, 0 rows affected (0.71 sec)
"""
我们在创建表的时候应该有一个字段作为主键用来标识数据的唯一性,并且该字段通常情况下就是'id'(编号)字段
	id nid sid pid gid uid
create table userinfo(uid int primary key,);
"""
#联合主键(多个字段组合 本质还是一个主键)
mysql> create table t5(id int,name varchar(32),pwd int,primary key(id,pwd));
Query OK, 0 rows affected (0.59 sec)

自增

关键字:auto_increment
该约束条件不能单独出现,并且一张表中只能出现一次,主要配合主键一起用。
mysql> create table t8(id int primary key,name varchar(32));
Query OK, 0 rows affected (0.60 sec)

mysql> create table t9(id int primary key auto_increment,name varchar(32));
Query OK, 0 rows affected (0.56 sec)
"""
自增特性:
	自增不会因为数据的删除而回退,永远自增向前
	如果自己设置了更大的数,则之后按照更大的数往前自增
	如果想重置某张表的主键值,可使用turncate t9;清空表数据并重置主键
	#格式化表
"""

优点:
	1.数据库自动编号,速度快且是增量增长。按顺序存放对于检索非常有利;
    2.数字型,占用空间小,易排序,在程序中传递也方便;
    3.如果通过非系统增加记录时,可以不用指定该字段,不用担心主键重复问题。

外键前戏

定义:
	外键约束即数据库中两个数据表之间的某个列建立的一种联系
作用:
	MySQL通过外键约束的引入,可以使得数据表中的数据完整性更强;保证数据的一致性。
"""
ps:
	与外键关联的主表的字段必须设置为主键;
	要求从表不能是临时表,主从表的字段具备相同的数据类型、字符长度和约束
"""
外键字段:用于标识数据与数据之间关系的字段

关系的判断

表关系、数据关系其实意思是一样的,只是说法上有区分
关系一共四种:
	一对多、多对多、一对一、没有关系
    关系的判断可以采用‘换位思考’原则

一对多关系
以员工表和部门表为例
	1.先站在员工表的角度
    	问:一名员工能否对应多个部门
       答:不可以
 	2.再站在部门表的角度
    	问:一个部门能否对应多名员工
     	答:可以	
	结论:一个可以一个不可以 那么关系就是'一对多'
	针对'一对多'关系 外键字段建在'多'的一方

外键字段的建立

小技巧:先定义出含有普通字段的表,之后再考虑外键字段的添加
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(64)
);
1.创建表的时候一定要先创建被关联表
2.录入表数据的时候一定要先录入被关联表
3.修改数据的时候外键字段无法修改和删除

针对3有简化措施>>>:级联更新级联删除
create table emp1(
	 id int primary key auto_increment,
 	 name varchar(32),
 	 age int,
 	 dep_id int,
	 foreign key(dep_id) references dep1(id) 
    on update cascade 
    on delete cascade
);

create table dep1(
	id int primary key auto_increment,
 	dep_name varchar(32),
  	dep_desc varchar(64)
);

"""
外键其实是强耦合 不符合解耦合的特性
	所以很多时候 实际项目中当表较多的情况 我们可能不会使用外键 而是使用代码建立逻辑层面的关系
"""

多对多关系

以书籍表与作者表为例
	1.先站在书籍表的角度
  		问:一本书能否对应多个作者
      答:可以
 	2.再站在作者表的角度
    	问:一个作者能否对应多本书
      	答:可以
   结论:两个都可以 关系就是'多对多'	
 	针对'多对多'不能在表中直接创建 需要新建第三张关系表
 
create table book(
	id int primary key auto_increment,
 	title varchar(32),
  	price float(5,2)
);
create table author(
	id int primary key auto_increment,
 	name varchar(32),
  	phone bigint
);
create table book2author(
	id int primary key auto_increment,
   author_id int,
 	foreign key(author_id) references author(id)
  	on update cascade
  	on delete cascade,
   book_id int,
  	foreign key(book_id) references book(id)
  	on update cascade
  	on delete cascade
);
mysql> desc book2author;
+-----------+---------+------+-----+---------+----------------+
| Field     | Type    | Null | Key | Default | Extra          |
+-----------+---------+------+-----+---------+----------------+
| id        | int(11) | NO   | PRI | NULL    | auto_increment |
| author_id | int(11) | YES  | MUL | NULL    |                |
| book_id   | int(11) | YES  | MUL | NULL    |                |
+-----------+---------+------+-----+---------+----------------+
3 rows in set (0.00 sec)

mysql> desc author;
+-------+-------------+------+-----+---------+----------------+
| Field | Type        | Null | Key | Default | Extra          |
+-------+-------------+------+-----+---------+----------------+
| id    | int(11)     | NO   | PRI | NULL    | auto_increment |
| name  | varchar(32) | YES  |     | NULL    |                |
| phone | bigint(20)  | YES  |     | NULL    |                |
+-------+-------------+------+-----+---------+----------------+
3 rows in set (0.02 sec)

mysql> desc book;
+-------+-------------+------+-----+---------+----------------+
| Field | Type        | Null | Key | Default | Extra          |
+-------+-------------+------+-----+---------+----------------+
| id    | int(11)     | NO   | PRI | NULL    | auto_increment |
| title | varchar(32) | YES  |     | NULL    |                |
| price | float(5,2)  | YES  |     | NULL    |                |
+-------+-------------+------+-----+---------+----------------+
3 rows in set (0.01 sec)


一对一关系

以用户表与用户详情表为例
	1.先站在用户表的角度
  		问:一个用户能否对应多个用户详情
      答:不可以
 	2.再站在用户详情表的角度
    	问:一个用户详情能否对应多个用户
      	答:不可以
   结论:两个都可以 关系就是'一对一'或者没有关系	
 	针对'一对一'外键字段建在任何一方都可以 但是推荐建在查询频率较高的表中
 
create table user(
	id int primary key auto_increment,
  	name varchar(32),
 	detail_id int unique,
  	foreign key(detail_id) references userdetail(id)
  	on update cascade
  	on delete cascade
);

create table userdetail(
	id int primary key auto_increment,
  	phone bigint
);

mysql> desc user;
+-----------+-------------+------+-----+---------+----------------+
| Field     | Type        | Null | Key | Default | Extra          |
+-----------+-------------+------+-----+---------+----------------+
| id        | int(11)     | NO   | PRI | NULL    | auto_increment |
| name      | varchar(32) | YES  |     | NULL    |                |
| detail_id | int(11)     | YES  | UNI | NULL    |                |
+-----------+-------------+------+-----+---------+----------------+
3 rows in set (0.01 sec)

mysql> desc userdetail;
+-------+------------+------+-----+---------+----------------+
| Field | Type       | Null | Key | Default | Extra          |
+-------+------------+------+-----+---------+----------------+
| id    | int(11)    | NO   | PRI | NULL    | auto_increment |
| phone | bigint(20) | YES  |     | NULL    |                |
+-------+------------+------+-----+---------+----------------+
2 rows in set (0.02 sec)

SQL语句查询关键字

select  # 选择,指定需要查询的字段信息
select * #查询所有字段
select name  #查name字段
select char_length(name) # 支持对字段做处理 

from #来自...
	# 指定需要查询的表信息
    from mysql.user
    from t1

SQL语句中关键字的执行顺序和编写顺序并不是一致的,可能会错乱。
	eg:
    select id,name from userinfo;
    我们先写的select再写的from,但是执行的时候是先执行的from再执行select
ps:
    对应关键字的编写顺序和执行顺序没必要过于在意,熟练之后会自然编写,只要把注意力放在每个关键字的功能上即可。

前期数据准备

mysql> create table emp(
    ->   id int primary key auto_increment,
    ->   name varchar(20) not null,
    ->   gender enum('male','female') not null default 'male', 
    #大部分是男的
    ->   age int(3) unsigned not null default 28,
    ->   hire_date date not null,
    ->   post varchar(50),
    ->   post_comment varchar(100),
    ->   salary double(15,2),
    ->   office int, #一个部门一个屋子
    ->   depart_id int
    -> );
Query OK, 0 rows affected (1.60 sec)

#插入记录
#三个部门:教学,销售,运营
mysql> insert into emp(name,gender,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);
Query OK, 18 rows affected (0.38 sec)

编写SQL语句的小技巧

1.select后面的字段名可以先用*占位往后写,最后再修改占位符替代的内容;
2.实际应用中select后面很少写*,因为*表示所有,如表中字段和数据都特别多的情况下会非常浪费数据库资源;
"""
SQL语句的编写类似于代码的编写,需要反复修改补充。
"""

查询关键字之where筛选

# 1.查询id大于等于3小于等于6的数据
mysql> select * from emp where id >=3 and id <=6;
4 rows in set (0.14 sec)
#支持逻辑运算符
mysql> select *from emp where id between 3 and 6;
4 rows in set (0.07 sec)

# 2.查询薪资是20000或者18000或者17000的数据
mysql> select * from emp where salary =20000 or salary=18000 or salary = 17000;
3 rows in set (0.01 sec)
mysql> select * from emp where salary in (20000,18000,17000);
3 rows in set (0.00 sec)

# 3.查询id小于3大于6的数据
mysql> select * from emp where id<3 or id>6;
mysql> select * from emp where id not between 3 and 6;

# 4.查询员工姓名中包含字母o的员工姓名与薪资
mysql> select * from emp where name like '%o%';

"""
条件不够精确的查询称为模糊查询,关键字为like
"""
#模糊查询常用符号:
	%:匹配任意个数的任意字符
    	例:%o%	o jason owen loo wwoww
        	%o	  o	asdasdo asdo
	_:匹配单个个数的任意字符
        例:_o_	aox	wob iok 
        	o_	 oi ok ol

# 5.查询员工姓名是由四个字符组成的员工姓名与其薪资
mysql> select * from emp where name like'____';
#四个下划线,一个下划线代表一个字符
mysql> select * from emp where char_length(name)=4;

# 6.查询岗位描述为空的员工名与岗位名(针对null不能用等号,只能用is)
mysql> select * from emp where post_comment=NULL;
Empty set (0.00 sec)# 找不到
mysql> select * from emp where post_comment is NULL;
18 rows in set (0.00 sec)

查询关键字之group by分组

分组:
	意思就是按照指定的条件将单个的数据分类再组成整体,目的也是为了更好地统计数据。
eg:将学生按照性别分组、将全国人民按照民族分组、将全部人类按照肤色分组

#聚合函数:专门用于分组之后的数据统计
"""
max\min\sum\avg\count
最大值、最小值、总和、平均数、计数
"""

1.将员工数据按照部门分组
mysql> select * from emp group by post;
"""
MySQL5.6默认不会报错
	set global sql_mode='strict_trans_tables,only_full_group_by'
MySQL5.7及8.0默认都会直接报错
	因为分组之后,select后面默认只能直接填写分组的依据,不能再写其他字段
		select post from emp group by post;
		select age from emp group by age;		
	分组之后默认的最小单位就应该是组,而不应该再是组内的单个数据单个字段
"""

2.获取每个部门的最高工资
# 判断是否需要分组可以从题目的需求中分析,特别是出现关键字(每个,平均)
mysql> select post,max(salary)from emp group by post;
"""
针对SQL语句执行之后的结果,可以修改字段名称,关键as也可以省略
select post as'部门',max(salary)as'最高薪资'from emp group by post;
"""

3.一次获取部门薪资相关统计
mysql> select post,max(salary) '最高薪',min(salary) '最低薪',avg(salary) '平均薪资',sum(salary) '月支出' from emp group by post;

4.统计每个部门的人数
mysql> select post,count(id) from emp group by post;

5.统计每个部门的部门名称以及部门下的员工姓名
mysql> select post,name from emp group by post;
mysql> select post,group_concat(name)from emp group by post;
mysql> select post ,group_concat(name,age) from emp group by post;

# 格式化输出,解压赋值
mysql> select post,group_concat(name,'|',age)from emp group by post;
mysql> select post,group_concat(name,'_NB')from emp group by post;
mysql> select post,group_concat('DSB_',name,'_NB')from emp group by post;

查询关键字之having过滤

having与where一样都用来对数据做筛选,但是where用在分组之前(首次筛选),having用在分组之后(二次筛选)
1.统计各部门年龄在30岁以上的员工平均工资,并且保留大于10000的数据
"""
	在写复杂的SQL时跟写代码一样,提前构思大致步骤,将每条SQL的结果看成一张表,基于该表如果还想继续操作则直接在产生该表的SQL语句上添加即可。
"""
	步骤1:先筛选出所有年龄大于30岁的员工数据
    	select * from emp where age > 30;
 	步骤2:再对筛选出来的数据按照部门分组并统计平均薪资
    	select post,avg(salary) from emp where age > 30 group by post;
 	步骤3:针对分组统计之后的结果做二次筛选
    	select post,avg(salary) from emp where age > 30 group by post having avg(salary) > 10000;

查询关键字之distinct去重

去重的必需条件:必须有一模一样的数据
mysql> select distinct id ,age from emp;
# 关键字针对多个字段组合的结果
mysql> select distinct age from emp;
# 去重成功
mysql> select distinct age,post from emp;
# 必须两个关键字数据都相同才能去重

查询关键字之order by排序

1.单个字段排序
mysql> select * from emp order by age;
# 默认升序
mysql> select * from emp order by age asc;
# 默认升序(asc可省略)
mysql> select * from emp order by age desc;
# 默认升序变降序

2.多个字段排序
mysql> select * from emp order by age,salary desc;
# 先按照年龄升序排,相同的情况下再按照薪资降序排

	# 统计各部门年龄在10岁以上的员工平均工资,并且保留平均工资大于1000的部门,然后对平均工资进行排序
1.先筛选出所有年龄大于10岁的员工
mysql> select * from emp where age>10;
2.再对他们按照部门分组统计平均薪资
mysql> select post,avg(salary)from emp where age>10 group by post;
3.针对分组的结果做二次筛选
mysql> select post,avg(salary)from emp where age>10 group by post having avg(salary)>10000;
4.最后按照指定字段排序
 	select post,avg(salary) from emp where age > 10 group by post having avg(salary)>1000 order by avg(salary);

查询关键字之limit分页

当表中数据特别多的情况下 我们很少会一次性获取所有的数据
	很多网站也是做了分页处理 一次性只能看一点点
  
select * from emp limit 5;  直接限制展示的条数
select * from emp limit 5,5;  从第5条开始往后读取5条

查询工资最高的人的详细信息
'''千万不要关系思维 一看到工资最高就想着用分组聚合'''
select * from emp order by salary desc limit 1;

查询关键字之regexp正则表达式

SQL语句的模糊匹配如果用不习惯 也可以自己写正则批量查询
	select * from emp where name regexp '^j.*?(n|y)$';

多表查询的思路

表数据准备
create table dep(
  id int primary key auto_increment,
  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,'运营'),
(205,'财务');

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


select * from emp,dep;  会将两张表中所有的数据对应一遍
这个现象我们也称之为'笛卡尔积' 无脑的对应没有意义 应该将有关系的数据对应到一起才合理
基于笛卡尔积可以将部门编号与部门id相同的数据筛选出来
涉及到两张及以上的表时 字段很容易冲突 我们需要在字段前面加上表名来指定
select * from emp,dep where emp.dep_id=dep.id;
基于上述的操作就可以将多张表合并到一起然后一次性获取更多的数据

标签:总结,name,int,本周,内容,mysql,线程,id,select
From: https://www.cnblogs.com/zhiliaowang/p/16930307.html

相关文章

  • 2022-2023-1 20221422 《计算机基础与程序设计》第十三周学习总结
    作业信息班级链接https://edu.cnblogs.com/campus/besti/2022-2023-1-CFAP作业要求https://www.cnblogs.com/rocedu/p/9577842.html这个作业的目标学习云班......
  • 第十三周学习总结
    #学期(如2022-2023-1)学号(如:20221426)《计算机基础与程序设计》第十三周学习总结##作业信息|这个作业属于哪个课程|<班级的链接>(如[2022-2023-1-计算机基础与程序设计](......
  • 第九周总结
    第九周总结线程线程理论进程进程其实是资源单位,表示的是一块内存空间线程线程是执行单位,表示真正的代码指令一个进程内部至少含有一个线程1.一个进程内可......
  • 11月的第4次周末总结
    本周内容总结线程理论#进程 进程其实是资源单位表示一块内存空间#线程 线程才是执行单位表示真正的代码指令我们可以将进程比喻成车间线程是车间里面的流......
  • # 2022-2023-1 20221415 《计算机基础与程序设计》第十三周学习总结
    2022-2023-120221415《计算机基础与程序设计》第十三周学习总结作业信息这个作业属于哪个课程<班级的链接>(2022-2023-1-计算机基础与程序设计)这个作业要求在......
  • vulnhub靶场隐写相关内容
    图片隐写steghideinfotrytofind.jpg#检测图片steghideextract-sftrytofind.jpg#提取图片隐写信息音频隐写工具下载地址:https://github.com/hacksudo/Soun......
  • 第九周内容回顾
    一、多进程实现TCP服务端并发通过之前的学习我们了解到可以使用process模块创建多进程,但是服务端在接收的时候如果跟之前一样的方式接收会出现端口被占用的报错提示,这时候......
  • 2022-2023-1 20221415 《计算机基础与程序设计》第十二周学习总结
    2022-2023-120221415《计算机基础与程序设计》第十二周学习总结作业信息这个作业属于哪个课程<班级的链接>(2022-2023-1-计算机基础与程序设计)这个作业要求在......
  • HTTP总结
    http的完整交互过程:当客服端第一向服务器发送请求的时候服务器处理请求给客服端响应,服务器会在响应的请求头里面加入一些东西,就上我在HTTP里面说的哪些在这里我就不重复了......
  • season5总结
    season5总结前言项目链接github:https://caokejian.github.io/Season-5/dist/腾讯云:(部署Xshell出现秘钥问题没有解决...)前端vue2+vuex·····从0开始的酒庄销售系......