数据库从入门到入坟

Posted Jeff的技术栈

tags:

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

一、数据库的类型

关系性数据库

mysql, oracle, sqlite, db2, sql server

​ 1.数据与数据之间可以有关联和限制的

​ 2.关系型数据库通常都是表结构,也就意味着你在用关系型数据库的时候,第一步就是确定表结构

非关系性数据库

​ redis,mongodb(文档型数据库 非常接近关系型的非关系型数据),memcache

​ 通常都是以k,v键值的形式 存储数据 类似字典

数据库编码

一般用utf8

utf8mb4:可以存表情

二、MySQL

启动前准备:

1.bin目录配置环境变量path中

2.管理员身份运行cmd,将bin目录下mysqld服务端制作成系统服务(自动开启,24小时不间断服务)

​ 制作命令: mysqld --install

服务端
mysqld

客户端
mysql

1.启动

1.启动mysqld 服务端
1.切换到bin目录下
2.执行mysqld
ps:做前期MySQL配置的时候 终端建议你用管理员身份运行

2.启动 mysql 客户端

客户端登陆
mysql -h 127.0.0.1 -P 3306 -uroot -p
可以简写
mysql -uroot -p

如果不输入用户名和密码 默认是访客模式登陆 所能用到的功能很少

客户端退出登陆
exit;
quit;

2.修改密码

没有密码的情况下
set password for root@localhost =password(\'123\'); 这个好用,亲身实验,老师讲的不成功

有密码的情况下
mysqladmin -uroot -p123 password 123456;

当命令输入错误的时候 可以用\\c取消前面的命令 cancel

密码忘记,破解密码

思路:密码验证就是一个装饰器,那么启动的时候跳过密码装饰器,密码就破解了

注意停止:先查PID号,再杀死进程

​ 1.先停止服务端,重启服务端,跳过用户名密码验证功能

​ 命令:mysqld --skip-grant-tables; 启动服务端,跳过授权表

​ 2.修改管理员用户对应的密码(而不是全部用户的密码,选择需要修改的用户)

​ 命令:uptade mysql.user set password = password(123) where user = \'root\' and host=\'localhost\';

​ host=\'localhost\' 表示 本地的服务器

​ 3.重新正常启动服务端(拥有密码验证的功能)

​ 4.客户端mysql正常登录到服务端(刚刚修改的密码)

3.配置文件

​ \\s:查看 mysql服务端简单配置
​ 通常情况下配置文件的后缀都是ini结尾

mysql自带的配置文件不要修改
但是你可以新建一个配置文件 my.ini
mysql服务端在启动就会自动加载你的my.ini配置文件内的配置

修改完配置文件之后需要先将服务端停止 重新启动 才能生效

修改了配置文件一定要重启服务端

[mysqld]
character-set-server=utf8
collation-server=utf8_general_ci

# 这个是用python软件连接的客户端
[client]
default-character-set=utf8

# mysql软件的客户端
[mysql]
# 可写,可不写这样可以不需要用户名与密码直接登录mysql
# user=\'root\'
# password=123

# 设置默认的字符编码
default-character-set=utf8

4.设置严格模式

严格模式:比如char(4),4个长度,但是存了5个进去,就会报错

如果不是严格模式,mysql会自动的截取最大长度来保存。

使用数据库原则:能尽量的让数据库少干活。因为量一大,数据库一旦崩溃,所有都完蛋

 show variables like "%mode%";   模糊查找一下
 
 
 set session  临时有效  只在你当前操作的窗口有效
  set global   全局有效  终生有效
  set global sql_mode = \'STRICT_TRANS_TABLES\';
  设置完之后 你只需要重新退出客户端再次进入即可
  
  
  """
show variables like "%mode%";
设置sql_mode为only_full_group_by,意味着以后但凡分组,只能取到分组的依据,
不应该在去取组里面的单个元素的值,那样的话分组就没有意义了,因为不分组就是对单个元素信息的随意获取
"""
set global sql_mode="strict_trans_tables,only_full_group_by";   #  修改模式
# 重新链接客户端

三.数据库的增删改查

批量入库 bulk_create和executemany

bulk_create

book_list = []
    for i in range(10000):
        book_list.append(models.Book(title=\'第%s书\' % i))
    models.Book.objects.bulk_create(book_list)
    #获得Book对象点批量插入数据方法,插入book_list列表的数据
    book_queryset = models.Book.objects.all()
    return render(request, \'index.html\', locals())

executemany批量插入

ip_list = [x,x,x,x,x,x,...]

sql = \'insert into ip_list(ip) values(%s)\'
cursor.executemany(sql,ip_list)
conn = pymysql.connect(
        host=\'127.0.0.1\',
        port=3306,
        user=\'root\',
        password=\'123\',
        database=\'pachong\',
        charset=\'utf8\',
        autocommit=True
    )
cursor = conn.cursor(pymysql.cursors.DictCursor)
ip_list = []
res = []
for i in range(10000):
    res.append(i)
sql = \'insert into ip_list(ip) values(%s)\'
cursor.executemany(sql,res)

execute 一次执行一条sql

sql = \'insert into ip_list(ip) values(%s)\'
cursor.execute(sql,ip)

1.库 类似于文件夹

        增
            create database 库名;   添加库
            create database 库名 charset utf8;   添加库定义编码
        查
            show databases;  查所有
            show create database 库名;  查单个
        改
            alter database 库名 charset=\'gbk\';  修改编码
        删
            drop database 库名;  删库

2.表 类似于文件

创建表的完整语法:

​ create table 表名(
​ 字段名1 字段类型[(宽度) 约束条件],
​ 字段名2 字段类型[(宽度) 约束条件],
​ 字段名3 字段类型[(宽度) 约束条件],
​ 字段名4 字段类型[(宽度) 约束条件]
​ );

​ 在创建表的时候 需要先指定库
​ 指定库: use 库名
​ 查看当前所在的库: select database()

清空表:
truncate table 表名; # 清空表
truncate 1.会重建表结构,清除主键 2.truncate 不能触发任何Delete触发

delete from 表名 仅仅是删除数据 不会重置主键
truncate table 表名 初始化表 会重置主键

增
    create table 表名(id int,name char);
	create table 表名(id int,name char(4)default \'jeff\');   # 给name属性添加默认值,用户不填的情况用默认
查
    show tables;  查看某个库下面的所有的表
    show create table 表名;    # 查单个表
    desc 表名;    <==> describe 表名;   # 查单个表
改
    alter table 表名 modify 字段名 char(32);
删
    drop table 表名;

3.记录

​ 先创建一个库或者指定一个已经存在的库
​ 切换到该库下 创建表
​ 然后再操作记录
​ create database 库名; # 创建库
​ create table 表名(id int,name char(32),password int); # 添加表

    增
        insert into 表名 values(1,\'jason\',123);  插入单条数据
        insert into 表名 values(1,\'jason\',123),(2,\'egon\',123),(3,\'tank\',123);  插入多条数据     
        insert into 表名(name,id) values (\'jeff\',1)   #  可以指定字段插入
    查
        select * from 表名;  查询所有的字段信息
        select name from 表名;  查询指定字段信息
        select id,name from 表名 where id=1 or name=\'tank\';  带有筛选条件的字段信息
    改
        update 表名 set name=\'kevin\' where id=1;  修改数据的一个字段信息
        update 表名 set name=\'jason\',password=666 where id=1;  修改数据的多个字段
    删
        delete from 表名 where id =1;  指定删符合条件的数据
        delete from 表名;  将表中的数据全部删除
   清空表:
    	truncate table 表名;   # 清空表
    	truncate 1.会重建表结构,清除主键  2.truncate 不能触发任何Delete触发器

4.查杀进程

查看所有的数据库
    show databases;

查看某个进程
    tasklist |findstr 名称

杀死进程
    taskkill /F /PID 进程号

5.修改表名、增加字段、删除字段、修改字段

1.修改表名

alter table 表名 rename 新表名;

2.增加字段

alter table 表名 add 字段名 数据类型 [完整性约束条件…],addD 字段名 数据类型 [完整性约束条件…];

3.移动字段次序

alter table 表名 add 字段名 数据类型 [完整性约束条件…] first; # 直接移到最前面

alter table 表名add 字段名 数据类型 [完整性约束条件…] after 字段名; # 寻找插哪个字段的后面

4.删除字段

alter table 表名 drop 字段名;

5.修改字段

modify只能改字段数据类型完整约束,不能改字段名,但是change可以!

alter table 表名 modify 字段名 数据类型 [完整性约束条件…];

alter table 表名 change 旧字段名 新字段名 新数据类型 [完整性约束条件…];

6.复制表

复制表结构+记录 (key不会复制: 主键、外键和索引)

create table new_service select * from service;

只复制表结构

select * from service where 1=2;        //条件为假,查不到任何记录

create table new1_service select * from service where 1=2;  

create table t4 like employees;

7.json数据格式查询

数据表

json测试数据:{"id": 618076, "mid":"123456"}

mysql:
目标:查询text字段中json数据的mid
方式一:结果带双引号(json数据中有双引号,查询结果就有双引号)
	select JSON_EXTRACT(text,\'$.mid\') from json_text
方式二:不带双引号
	select text ->> \'$.mid\' from json_text 
	
pg:
	select text::json-> \'mid\' FROM json_text

四、存储引擎

不同的数据应该有不同的处理机制

mysql存储引擎
Innodb: 5.5之后默认的存储引擎 查询速度较myisam慢 但是更安全,支持事务,支持行锁,支持外键 行锁:同一时间只能一个用户操作这行数据 2两个文件

​ myisam: mysql老版本用的存储引擎 5.5之前 3个文件
​ memory: 内存引擎(数据全部存在内存中),断电或者服务端重启之后所有数据都没有了 1个文件
​ blackhole: 无论存什么 都立马消失(黑洞) 1个文件

研究一下每个存储引擎存取数据的特点
​ show engines;

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;

五、数据类型

1.常用数据类型

只有Int整型不需要指定宽度 因为默认的宽度 足够显示对应的数据

#1. 数字:
    整型:tinyinit  int  bigint
    小数:
        float :在位数比较短的情况下不精准
        double :在位数比较长的情况下不精准
            0.000001230123123123
            存成:0.000001230000

        decimal:(如果用小数,则用推荐使用decimal)
            精准
            内部原理是以字符串形式去存
         unsigned  没有符号的整型,正整数
        age int(3) unsigned not null default 28

#2. 字符串:
    char(10):简单粗暴,浪费空间,存取速度快
        root存成root000000
    varchar:精准,节省空间,存取速度慢

    sql优化:创建表时,定长的类型往前放,变长的往后放
                    比如性别           比如地址或描述信息

    >255个字符,超了就把文件路径存放到数据库中。
            比如图片,视频等找一个文件服务器,数据库中只存路径或url。



#3. 时间类型:
    最常用:datetime


#4. 枚举类型与集合类型
	枚举(enum)  限制某个字段能够存储的数据内容
    集合(set)   限制某个字段能够存储的数据内容

2.数值类型

1.整数类型

tinyint smallint mediumint int bigint

int 不用设置宽度,因为默认值够大

2.浮点型

​ float(255,30) 总共255位 小数部分占30位
​ double(255,30) 总共255位 小数部分占30位
​ decimal(65,30) 总共65位 小数部分占30位

精确度:float<double<decimal

 create table t12(id FLOAT(255,30));
  create table t13(id DOUBLE(255,30));
  create table t14(id DECIMAL(65,30));
  
  	  insert into t12 values(1.111111111111111111111111111111);
      insert into t13 values(1.111111111111111111111111111111);
      insert into t14 values(1.111111111111111111111111111111);

六、日期类型

date time datetime timestamp year

date: 年月日

time:几时几分几秒

datetime:年月日时分秒

timestamp:时间戳

year:年份

七、字符串类型

char,varchar

1.char(N) 定长

用于保存固定长度的字符串,不足的用空格补全,N的范围0~255

特点:好存好取,浪费空间

2.varchar(N) 变长

用于保存变长字符类型,N的范围0~65535

特点:不好存不好取,节约空间

八、枚举类型与集合类型

字段的值只能在给定的范围中选择,比如单选框、多选框

enum 单选 只能在给定的范围选一个值,如性别选择

set 多选 在给定的范围内可以选择一个或者多个值(爱好1,爱好2,爱好3)

示例:单选 enum

              create table gyy (
                    name varchar(40),
                    size enum(\'x-small\', \'small\', \'medium\', \'large\', \'x-large\')
                );    #  在给定的范围内选择
                
                insert into gyy (name, size) values (\'dress shirt\',\'large\'), (\'t-shirt\',\'medium\'),(\'polo shirt\',\'small\');

实例: 集合 set

CREATE TABLE myset (col SET(\'a\', \'b\', \'c\', \'d\'));  # 在给定的范围内选择

INSERT INTO myset (col) VALUES (\'a,d\'), (\'d,a\'), (\'a,d,a\'), (\'a,d,d\'), (\'d,a,d\');

九、约束

1.not null

not null 不能为空

2.default 默认值

给某个 字段设置默认值(当用户填写的时候使用用户的,不填写使用默认的)

create table biao1(id int,name char(4) default\'jeff\');# name选项不填写默认jeff

3.unique 唯一

单列唯一 限制某一个字段事唯一的

​ id int unique

联合唯一 (在语句的最后 用括号的形式 表示哪几个字段组合的结果是唯一的)

使用方法:

 create table server(
        id int,
       ip char(16),
       port int,
       unique(ip,port)
     )

4.primary key主键

主键:一般设置在id或者编号,具有唯一且默认递增,与auto_increment配合使用

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

primary key 也是innidb引擎查询的索引

限制效果跟 not null + unique 非空且唯一 组合效果一至

使用方法:

create table biao(id int primary key);
  innodb引擎在创建表的时候 必须要有一个主键
  当你没有指定主键的时候
     1.会将非空切唯一的字段自动升级成主键
     2.当你的表中没有任何的约束条件  innodb会采用自己的内部默认的一个主键字段
        该主键字段你在查询时候是无法使用的
        查询数据的速度就会很慢
        类似于一页一页的翻书
        
   联合主键:多个字段联合起来作为表的一个主键,本质还是一个主键!!!
     !!!!!!!!!!!!!!!!!ps:innodb引擎中一张表有且只有一个主键!!!!!!!!!!!!!!!!!!!!!!!
        
 联合主键: ip+端口为主键       
   create table biao(
            ip char(16),
           port int,
           primary key(ip,port)
         );

delete from 表名 仅仅是删除数据 不会重置主键
truncate table 表名 初始化表 会重置主键

5.primary key主键自动递增

create table t66(id int auto_increment,name char(16),primary key(id));  # 创建表


# 第一种方法,不选择id主键字段
 insert into t66(name) values(\'jeff\');
 
 # 第二种方法,用0占位
 insert into t66 values(0,\'jeff\');

6.auto_increment 递增

auto_increment 自动递增,只能加载到key字段上 key:主键,唯一,外键

  主键字段应该具备自动递增的特点
     每次添加数据  不需要用户手动输入
     auto_increment  自动递增
  create table t21(id int primary key auto_increment,name varchar(16));

delete from 表名; 将表中的数据全部删除。没有清空主键

清空表:
truncate table 表名; # 清空表
truncate 1.会重建表结构,清除主键 2.truncate 不能触发任何Delete触发器

十、外键

判断外键关系

外键的关键字:

​ foreign key(自己id) references 别的表名(别的表名的字段) 只是用来建表关系的

foreign key(author_id) references author(id)
表示:当前表的author_id与author表的id字段关联

外键约束:

​ 1.在创建表的时候必须先创建被关联的表

​ 2.插入数据的时候 也必须先插入被关联表的数据

1.外键——表关系判断

判断表关系最简单的语法:

​ 图书馆与出版社

​ 一本书可不可以有多个出版社 不可以!!!

​ 一个出版社可不可以出版多本书 可以!!!

​ 一对多的关系

​ 图书与作者

​ 一本书可不可以有多个作者 可以!!!

​ 一个作者可不可以写多本书 可以!!!

​ 多对多的关系

​ 作者与作者详情

​ 一个作者可不可以有多个详情 不可以!!!

​ 一个详情可不可以有多个作者 不可以!!!

​ 两者要么一对一的关系

​ 两者要么没关系

2.外键——连级更新

​ foreign key(dep_id) references dep(id) 绑定关系

​ on update cascade 连级更新

​ on delete cascade 连级删除

	create table emp(
				id int primary key auto_increment,   # 设置主键、自动递增
				emp_name varchar(64),
				emp_gender enum(\'male\',\'female\',\'others\') default \'male\',
				dep_id int,
				foreign key(dep_id) references dep(id) 
				on update cascade   # 连级更新
				on delete cascade	# 连级删除
			);

3.外键——一对多

语法:

1.先建被关联的表

create table press(
		id int primary key auto_increment,    # 给id设置主键和自动增长
    	p_name varchar(10)
);

2.建关联的表:

create table library(
		id int primary key auto_increment,    # 给id设置主键和自动增长
    	l_name varchar(10),
    	l_price int,
    	press_id int,
    	foreign key(press_id)references press(id)   # 关联的字段
    	on update cascade   # 连级更新
		on delete cascade   # 连级删除
);

3.先插入被关联的表数据:

insert into press(address) values(\'清华出版社\'),(\'上海出版社\'),(\'北京出版社\');

4.插入关联数据表:

insert into library(l_name,l_prince,press_id) values(\'天下无贼\',128,1),
												(\'亲爱的可\',666,1),
												(\'西游记\',99,2),
												(\'骆驼祥子\',168,3),
												(\'情深深雨蒙蒙\',98,3);

4.外键——多对多

一本书可以拥有多个作者,一个作者可以写多本书

建表思路:因为是多对多的关系,比如先建图书表,那么图书表的作者writer字段必须是writer表的writer_id字段中的,但是writer表还没有建立,没有。同样的道理先建writer作者表,那么图书表还没有建立。所以关系建立在第三张表中,这两个表先建立,不设外键

语法:

1.先建两个普通的表,不需要设置外键

# 图书表
create table library(
    		id int primary key auto_increment,
    		name char(5),
    		price int,
);

# 作者表
create table writer(
			id int primary key auto_increment,
    		name char(10),
    		age int
);

2.建立关系表

create table library2writer(
			id int prinmary key auto_increment,
    		library_id int,
    		foreign key(library_id)references library(id)
    		on update cascade
    		on delete cascade,	
    		writer_id int,
    		foreign key(writer_id)references writer(id)
    		on update cascade
    		on delete cascade
		);

3.插入数据

# 图书表
insert into library(name,prince) values(\'天下无贼\',99),(\'西游记\',\'66\'),(\'骆驼祥子\',128);
# 作者表
insert into writer(name,age) values(\'jeff\',18),(\'gyy\',20),(\'cheary\',3);
# 关系表
insert into library2writer(library_id,writer_id)values(1,1),(1,2),(2,1),(2,2),(3,3);

5.外键——一对一

语法:

 # 建立作者详细信息表
    create table xiangqin(
    		id int primary key auto_increment,
        	prize char(30),
        	event varchar(100)
    );
    

# 建立作者表
create table writer1(
			id int primary key auto_increment,
    		name char(10),
    		age int
    		xiangqin_id int unique,   # 唯一
    		foreign key (xiangqin_id)references xiangqin(id)   # 绑定关系
    		on update cascade
    		on delete cascade
    
		);
     

6.关系总结

​ 通常将关系字段 称之为 外键字段
​ 一对多的外键字段 建在多的一方
​ 多对多 建在第三张表了
​ 一对一 外键字段建在任意一方都可以 但是推荐你建在查询频率较高的一方

7.练习题

练习:

# 班级表
cid	caption
# 学生表
sid sname gender class_id
# 老师表
tid	tname
# 课程表
cid	cname	teacher_id
# 成绩表
sid	student_id course_id number

十一、基本查询语法及方法

准备的表:

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), #以下是教学部
(\'egon\',\'male\',78,\'20150302\',\'teacher\',1000000.31,401,1),
(\'kevin\',\'male\',81,\'20130305\',\'teacher\',8300,401,1),
(\'tank\',\'male\',73,\'20140701\',\'teacher\',3500,401,1),
(\'owen\',\'male\',28,\'20121101\',\'teacher\',2100,401,1),
(\'jerry\',\'female\',18,\'20110211\',\'teacher\',9000,401,1),
(\'nick\',\'male\',18,\'19000301\',\'teacher\',30000,401,1),
(\'sean\',\'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)
;

#ps:如果在windows系统中,插入中文字符,select的结果为空白,可以将所有字符编码统一设置成gbk

​ from
​ where
​ group by
​ having
​ distinct
​ order by
​ limit

连表
inner join
left join
right join
union

1.书写顺序:

执行顺序:

from # 确定是那张表

where # 条件,筛选数据

select # 筛选之后拿出某些字段

2.where

1.查询id大于等于3小于等于6的数据

select * from emp where id >= 3 and id <= 6;
select * from emp where id between 3 and 6;
# 两者语句完全等价   between : 之间

2.查询薪资是20000或者18000或者17000的数据

salary in (20000,18000,17000);

select id,name from emp where salary = 20000 or salary = 18000 or salary = 17000;
select id,name from emp where salary in (20000,18000,17000);

3.查询员工姓名中包含o字母的员工姓名和薪资

模糊匹配  like
	%:匹配多个任意字符
	_:匹配一个任意字符
select name,salary from emp where name like \'%o%\';

4.查询员工姓名是由四个字符组成的员工姓名与其薪资

char_length :计算字段的长度

select name,salary from emp where name like \'____\';
select name,salary from emp where char_length(name) = 4;

5.查询id小于3或者大于6的数据

select * from emp where id < 3 or id > 6;
select * from emp where id not between 3 and 6;

6.查询薪资不在20000,18000,17000范围的数据

select id,name from emp where salary not in (20000,18000,17000);

7.查询岗位描述为空的员工名与岗位名 针对null判断的时候只能用is 不能用=

select name,post from emp where post_comment = Null;
select name,post from emp where post_comment is Null;

3.group by 分组

MySQL中分组之后 只能拿到分组的字段信息 无法直接获取其他字段信息,但是你可以通过其他方法(聚合函数)简介的获取

聚合函数 max min avg sum count

# 数据分组应用场景:每个部门的平均薪资,男女比例等

# 1.按部门分组
select * from emp group by post;  # 分组后取出的是每个组的第一条数据
select id,name,sex from emp group by post;  # 验证
"""
show variables like "%mode%";
设置sql_mode为only_full_group_by,意味着以后但凡分组,只能取到分组的依据,
不应该在去取组里面的单个元素的值,那样的话分组就没有意义了,因为不分组就是对单个元素信息的随意获取
"""
set global sql_mode="strict_trans_tables,only_full_group_by";   #  修改模式
# 重新链接客户端
select * from emp group by post;  # 报错
select id,name,sex from emp group by post;  # 报错
select post from emp group by post;  # 获取部门信息
# 强调:只要分组了,就不能够再“直接”查找到单个数据信息了,只能获取到组名


# 2.获取每个部门的最高工资  
# 以组为单位统计组内数据>>>聚合查询(聚集到一起合成为一个结果)
# 每个部门的最高工资
select post,max(salary) from emp group by post;
# 每个部门的最低工资
select post,min(salary) from emp group by post;
# 每个部门的平均工资
select post,avg(salary) from emp group by post;
# 每个部门的工资总和
select post,sum(salary) from emp group by post;
# 每个部门的人数
select post,count(id) from emp group by post;

# 3.查询分组之后的部门名称和每个部门下所有的学生姓名
# group_concat(分组之后用)不仅可以用来显示除分组外字段还有拼接字符串的作用
select post,group_concat(name) from emp group by post;

select post,group_concat(name,"_SB") from emp group by post;

select post,group_concat(name,": ",salary) from emp group by post;

select post,group_concat(salary) from emp group by post;

concat_ws(\':\',name,age,salary)    # 每个字段以冒号分隔

# 4.补充concat(不分组时用)拼接字符串达到更好的显示效果 as语法使用
select name as 姓名,salary as 薪资 from emp;
select concat("NAME: ",name) as 姓名,concat("SAL: ",salary) as 薪资 from emp;

# 补充as语法 即可以给字段起别名也可以给表起
select emp.id,emp.name from emp as t1; # 报错  因为表名已经被你改成了t1
select t1.id,t1.name from emp as t1;

# 查询四则运算
# 查询每个人的年薪
select name,salary*12 as annual_salary from emp;
select name,salary*12 annual_salary from emp;  # as可以省略

练习题:

# 刚开始查询表,一定要按照最基本的步骤,先确定是哪张表,再确定查这张表也没有限制条件,再确定是否需要分类,最后再确定需要什么字段对应的信息

1. 查询部门名以及部门包含的所有员工名字
2. 查询部门名以及各部门内包含的员工个数
3. 查询公司内男员工和女员工的个数
4. 查询部门名以及各部门的平均薪资
5. 查询部门名以及各部门的最高薪资
6. 查询部门名以及各部门的最低薪资
7. 查询男员工与男员工的平均薪资,女员工与女员工的平均薪资
"""
参考答案:
select post,group_concat(name) from emp group by post;
select post,count(id) from emp group by post;
select sex,count(id) from employee group by sex;
select post,avg(salary) from emp group by post;
select post,max(salary) from employee group by post;
select post,min(salary) from employee group by post;
select sex,avg(salary) from employee group by sex;
"""

# 关键字where group by同时出现的情况下,group by必须在where之后
# where先对整张表进行一次筛选,如何group by再对筛选过后的表进行分组
# 如何验证where是在group by之前执行而不是之后 利用聚合函数 因为聚合函数只能在分组之后才能使用
select id,name,age from emp where max(salary) > 3000;  # 报错!

select max(salary) from emp;  
# 正常运行,不分组意味着每一个人都是一组,等运行到max(salary)的时候已经经过where,group by操作了,只不过我们都没有写这些条件

# 语法顺序
select
from
where
group by

# 再识执行顺序
from
where 
group by
select


8、统计各部门年龄在30岁以上的员工平均工资
select post,avg(salary) from emp where age > 30 group by post; 
# 对where过滤出来的虚拟表进行一个分组

# 还不明白可以分步执行查看结构
select * from emp where age>30;
# 基于上面的虚拟表进行分组
select * from emp where age>=30 group by post;

4.having

截止目前已经学习的语法

select 查询字段1,查询字段2,... from 表名
		where 过滤条件
		group by分组依据

# 语法这么写,但是执行顺序却不一样
from
where
group by
select

having的语法格式与where一致,只不过having是在分组之后进行的过滤,即where虽然不能用聚合函数,但是having可以!

1、统计各部门年龄在30岁以上的员工平均工资,并且保留平均工资大于10000的部门
select post,avg(salary) from emp
        where age >= 30
        group by post
        having avg(salary) > 10000;
# 如果不信你可以将having取掉,查看结果,对比即可验证having用法!

#强调:having必须在group by后面使用
select * from emp having avg(salary) > 10000;  # 报错

5.distinct 去重复

# 对有重复的展示数据进行去重操作
select distinct post from emp;
SELECT DISTINCT ON (content, comment_name) *
  FROM comment_taobao1
 WHERE shoping_id = \'612187292549\'
 
 
 content, comment_name组合去重

6.order by 排序

select * from emp order by salary asc; #默认升序排
select * from emp order by salary desc; #降序排

select * from emp order by age desc; #降序排

#先按照age降序排,在年龄相同的情况下再按照薪资升序排
select * from emp order by age desc,salary asc; 

# 统计各部门年龄在30岁以上的员工平均工资,并且保留平均工资大于1000的部门,然后对平均工资进行排序
select post,avg(salary) from emp
    where age > 30
    group by post
    having avg(salary) > 1000
    order by avg(salary)
    ;

7.limit 限制显示几条

limit 5; 表示限制的个数

limit 5,5; 第一个参数,表示起始位置,第二个参数表示个数

# 限制展示条数
select * from emp limit 3;
# 查询工资最高的人的详细信息
select * from emp order by salary desc limit 1;

# 分页显示
select * from emp limit 0,5;  # 第一个参数表示起始位置,第二个参数表示的是条数,不是索引位置
select * from emp limit 5,5;

8.正则

select * from emp where name regexp \'^j.*(n|y)$\';


9.like

%: 模糊匹配

_ : 匹配一个字符

char_length(name) = 4, 计算字符长度

select * from teacher where tname like\'李%\'     # 以李开头的所有
select * from teacher where tname like\'%李\'     # 以李结尾的所有
select * from teacher where tname like\'%李%\'		# 匹配包含李的所有

多表查询

查询分为两大类:

1.联表查询 把两个表拼在一起查
2.子查询 将一张表的查询结果作为另外一个sql语句的查询条件

​ 拿到一个表的相关数据,到另一个表中查

表创建

#建表
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\',38,201),
(\'nick\',\'female\',28,202),
(\'owen\',\'male\',18,200),
(\'jerry\',\'female\',18,204)
;

# 当初为什么我们要分表,就是为了方便管理,在硬盘上确实是多张表,但是到了内存中我们应该把他们再拼成一张表进行查询才合理

联表查询 inner join

select * from emp,dep;  # 左表一条记录与右表所有记录都对应一遍>>>笛卡尔积

# 将所有的数据都对应了一遍,虽然不合理但是其中有合理的数据,现在我们需要做的就是找出合理的数据

# 查询员工及所在部门的信息
select * from emp,dep where emp.dep_id = dep.id;
# 查询部门为技术部的员工及部门信息
select * from emp,dep where emp.dep_id = dep.id and dep.name = \'技术\';


# 将两张表关联到一起的操作,有专门对应的方法
# 1、内连接:只取两张表有对应关系的记录    inner join
select * from emp inner join dep on emp.dep_id = dep.id;
select * from emp inner join dep on emp.dep_id = dep.id
                            where dep.name = "技术";

# 2、左连接: 在内连接的基础上保留左表没有对应关系的记录   left join
select * from emp left join dep on emp.dep_id = dep.id;

# 3、右连接: 在内连接的基础上保留右表没有对应关系的记录   reght join
select * from emp right join dep on emp.dep_id = dep.id;

# 4、全连接:在内连接的基础上保留左、右面表没有对应关系的的记录   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;

子查询

as 后面是取别名

# 就是将一个查询语句的结果用括号括起来当作另外一个查询语句的条件去用
# 1.查询部门是技术或者人力资源的员工信息
"""
先获取技术部和人力资源部的id号,再去员工表里面根据前面的id筛选出符合要求的员工信息
"""
select * from emp where dep_id in (select id from dep where name = "技术" or name = "人力资源");

# 2.每个部门最新入职的员工 思路:先查每个部门最新入职的员工,再按部门对应上联表查询
select t1.id,t1.name,t1.hire_date,t1.post,t2.* from emp as t1
inner join
(select post,max(hire_date) as max_date from emp group by post) as t2
on t1.post = t2.post
where t1.hire_date = t2.max_date
;

"""
记住一个规律,表的查询结果可以作为其他表的查询条件,也可以通过其别名的方式把它作为一张虚拟表去跟其他表做关联查询
"""

select * from emp inner join dep on emp.dep_id = dep.id;

exist(了解)

EXISTS关字键字表示存在。在使用EXISTS关键字时,内层查询语句不返回查询的记录,
而是返回一个真假值,True或False。
当返回True时,外层查询语句将进行查询
当返回值为False时,外层查询语句不进行查询。
select * from emp
where exists
(select id from dep where id > 203);

十二、数据库高级功能

1.视图

语法:create view 新建的视图名 as 连表

新建的视图名:表1_表2 (一般根据命名规范)

注意:

1.视图只有表结构,视图中的数据还是来源于原来的表
2.不要改动视图表中的数据
3.一般情况下不会频繁的使用视图来写业务逻辑

1.什么是视图?

一个查询语句的结果是一张虚拟表,将这种虚拟表保存下来,它就变成了一个视图

2.为什么要使用视图?

当平凡需要使用到多张表的连表结果,你就可以事先 生成号视图之后直接调用即可,避免反复写连表操作的sql语句。

3.如何使用?

# 1.这是一张连表
select * from teacher inner join course on teacher.tid = course.teacher_id;  
# 2.把连表另外生成一张表,就叫视图
create view teacher_course as 跟上面的连表


4.开发过程中会不会频繁的使用视图?

不会!视图是mysql的功能,如果你的项目里面大量的使用到了视图,那意味着你后期想要扩张某个功能的时候这个功能恰巧又需要对视图进行修改,意味着你需要先在mysql这边将视图先修改一下,然后再去应用程序中修改对应的sql语句,这就涉及到跨部门沟通的问题,所以通常不会使用视图,而是通过重新修改sql语句来扩展功能

2.触发器

1.什么是触发器?

触发器就是当达到某种条件自动触发

当你在对数据进行增删改的情况下会自动触发触发器,执行代码

2.触发器分为六种情况

之前:before 之后:after

增加前、增加后 before insert 、 after insert

删除前、删除后 before delete 、after delete

修改前、修改后 before update 、after updata

3.触发期命名规范

见名知意:

固定语法结构:

   create trigger 触发器的名字 after/before insert/update/delete on 表名 for each row
            begin
                sql语句
            end

可以修改MySQL默认的结束符(

以上是关于数据库从入门到入坟的主要内容,如果未能解决你的问题,请参考以下文章

超全面的线段树:从入门到入坟

数据库从入门到入坟

OpenCV从入门到入坟

Java从入门到入坟系列学习路线目录索引(持续更新中~~~)

Java从入门到入坟系列学习路线目录索引(持续更新中~~~)

《HTML从入门到入坟》第一期