python正则表达式和数据库

正则表达式和数据库

5.正则表达式

正则表达式,又称规则表达式**。**(英语:Regular Expression,在代码中常简写为regex、regexp或RE),计算机科学的一个概念。正则表达式通常被用来检索、替换那些符合某个模式(规则)的文本。

python正则表达式和数据库_第1张图片

python正则表达式和数据库_第2张图片

re模块的高级用法

1. search

re.search函数会在字符串内查找模式匹配,只要找到第一个匹配然后返回,如果字符串没有匹配,则返回None。

格式:re.search(pattern, string, flags=0)

需求:匹配出文章阅读的次数

#coding=utf-8
import re

ret = re.search(r"\d+", "阅读次数为 9999")
ret.group()

运行结果:

'9999'

match()和search()的区别:

match()函数只检测RE是不是在string的开始位置匹配,search()会扫描整个string查找匹配;

也就是说match()只有在0位置匹配成功的话才有返回,如果不是开始位置匹配成功的话,match()就返回none。

如:print(re.match(‘super’, ‘superstition’).span()) 会返回(0, 5)

print(re.match(‘super’, ‘insuperable’))   则返回None

如:print(re.search(‘super’, ‘superstition’).span())返回(0, 5)

print(re.search(‘super’, ‘insuperable’).span())返回(2, 7)

2. findall

re.findall遍历匹配,可以获取字符串中所有匹配的字符串,返回一个列表。

格式:re.findall(pattern, string, flags=0)

需求:统计出文章阅读的次数,转发次数,评论次数

#coding=utf-8
import re

ret = re.findall(r"\d+", "阅读次数:9999次,转发次数:883次,评论次数:3次")
print(ret)

运行结果:

['9999', '883', '3']

3. sub

使用re替换string中每一个匹配的子串后返回替换后的字符串。

格式:re.sub(pattern, repl, string, count)

需求:将匹配到的阅读次数加1

方法1:

#coding=utf-8
import re

ret = re.sub(r"\d+", "10000", "阅读次数:9999次,转发次数:883次,评论次数:3次")
print(ret)

运行结果:

阅读次数:10000,转发次数:10000,评论次数:10000

方法2:

#coding=utf-8
import re

def add(temp):
	strNum = temp.group()
	num = int(strNum) + 1
	return str(num)

ret = re.sub(r"\d+", add, "python = 997")
print(ret)

ret = re.sub(r"\d+", add, "python = 99")
print(ret)

运行结果:

python = 998
python = 100

4. split

按照能够匹配的子串将string分割后返回列表。

可以使用re.split来分割字符串,如:re.split(r’\s+’, text);将字符串按空格分割成一个单词列表。

格式:re.split(pattern, string[, maxsplit])

需求:切割字符串“info:xiaoZhang 33 shandong”

#coding=utf-8
import re

ret = re.split(r":| ","info:xiaoZhang 33 shandong")
print(ret)


运行结果:

['info', 'xiaoZhang', '33', 'shandong']

r的作用

Python中在正则字符串前面加上 ‘r‘ 表示,

让正则中的 ‘’ 不再具有转义功能(默认为转义),就是表示原生字含义一个斜杠 \

python贪婪和非贪婪

Python里数量词默认是贪婪的(在少数语言里也可能是默认非贪婪),总是尝试匹配尽可能多的字符;

非贪婪则相反,总是尝试匹配尽可能少的字符。

在"*","?","+","{m,n}"后面加上?,使贪婪变成非贪婪。

import re

# 匹配多个数字
result = re.match(r"aaa(\d+)", "aaa123456")
if result:
    print(result.group())
else:
    print("匹配失败~!")

匹配的结果:

aaa123456

6.数据库(mysql)

1. 数据库概述

数据库( Database )是按照数据结构组织存储管理数据的仓库 。 数据按照特定的格式存储起来,用户可以通过SQL(Structured Query Language)对数据库中的数据进行增删改查操作, 这比咱们之前使用文件来管理数据要方便得多。

  • 数据库 & 表

数据库管理系统(DataBase Manager System ) , 简称 DBMS , 是指一种操作和管理数据库的软件,这类软件用于创建、使用、维护数据库,对数据库进行统一管理和控制,以保证数据的完整性和安全性。我们可以通过它访问数据库中的表数据

数据库其实是存储数据的仓库,在数据库中有数据表,我们所存的数据其实都是往数据表里面存储,而数据库又管理着很多张表,表示这几张表是一批数据的集合。正如我们之前使用txt文件存储学生数据一样,如果使用数据库来存储,我们就会有一个表叫做student表,如果还需要存储教师信息,那么还应该有一个teacher表 ,而这两张表正好位于一个数据库中。

python正则表达式和数据库_第3张图片

  • 常见的数据库 SQL 适合做
  1. mysql 开源免费 , 小型数据库, oracle收购
  2. oracle 收费 ,大型数据库,oracle公司产品
  3. sql server 收费 微软产品
  4. SQLite 嵌入式小数据库 、 移动端常用(Android | ios)
  5. DB2 收费 , IBM 产品
  6. H2 开源 ,嵌入式 | 内存版 数据库,纯java实现

以上数据库都是关系型数据库 —> 里面存储的数据,可以建立关系。

非关系型数据库。 No Sql not only sql 不仅仅是sql 适合做缓存 购物车

mogodb redis

2. MySql 安装

  • mysql安装

    mysql -uroot -p123456

    -u : 表示username的意思

    -p : 表示password的意思

  • 可视化工具安装

3. 数据库操作

  • SQL分类:
SQL : Structrued Query Language 结构化的查询语言

    DDL : 数据定义语言,定义数据库/表结构 : create创建,drop删除,alter修改,truncate截断
    DML : 数据操纵语言,操作的是数据     : insert插入,update更新,delete删除
    DCL : 数据库控制语言,控制的权限相关  : grant(授权) ,revoke(取消授权)
    DQL : 数据查询语言,查询数据         : select查询
    
增删改查 CRUD
数据库
	创建数据库,删除数据库,修改数据库,查看数据库
表
	创建表,修改表,删除表,查看表
表中数据
	插入数据,修改数据,删除数据,查询数据

  • 创建数据库
create database xxx;
  • 删除数据库
drop database xxx;
  • 修改数据库
# 一般很少修改数据库 , 如果修改,只会修改数据库的编码,这一般很少修改。
alter database xxx character set gbk;

alter database xxx character set utf8;
  • 显示数据库
show databases;

# 显示这个数据库创建的语句,以及编码是什么
show create database xxxx; 

4.字段类型介绍

create table 表名 (
	列名 列的类型,
    列名 列的类型
)

数字类型:
        int				
        float			
        double
字符类型:        
		char		固定长度(即便长度不够,会补空格) char(10) hello
		varchar     可变长度 (数据多长,长度多长)   varchar(10) hello
日期类型:
		date(日期) 2019-03-17
		time(时间) 13:40:42
		datetime (日期和时间) 2019-03-17 13:40:42
        timestamp(日期时间) 2019-03-17 13:40:42

文件类型:
	BLOB : 二进制类型
	TEXT : 文本类型  
	
create table student(
    sid int,
    name varchar(20),
    high float(5,2) 
    );	

5. 数据库表操作

先使用可视化工具演练过一次后,再使用命令演示

  • 创建数据表
语法: create table 表名(
			字段名  类型(长度)[约束] ,
            字段名 类型(长度)[约束]
            );

CREATE TABLE aa (id INTEGER PRIMARY KEY AUTO_INCREMENT , username VARCHAR(25));
  • 删除数据表
语法: drop table 表名

DROP TABLE aa;   -- 删除表,一切都消失
  • 修改数据表
alter table 表名 add 列名 类型(长度) 约束; 		--修改表添加列. 
alter table 表名 modify 列名 类型(长度) 约束;	--修改列的类型长度及约束.
alter table 表名 change 旧列名 新列名 类型(长度) 约束;	--修改列名.
alter table 表名 drop 列名;					--删除列.
rename table 表名 to 新表名;					--修改表名(比较少用)
  • 显示数据表
show tables ; -- 显示当前数据库的所有表

desc  aa;  --查看具体某张表的结构

show create table aa; --显示建表语句

6. 约束介绍

  • 主键约束:primary key

关键字(primary key) 是表中的一个或多个字段,它的值用于唯一地标识表中的某一条记录 。 比如如何突出一名学生的唯一性,一般我们采用学号来表示,如何表示一个人的唯一,我们可以使用身份证号来表示。但是在数据库范畴里面,表示一条记录的唯一,我们通过会增加id 列来表示主键。

主键必须是唯一、 不能为空 , 可以设置为自增长。

# 主键约束可以在建表的时候就给定
create table stu(
    id int primary key auto_increment ,
    name varchar(25));

# 也可以后面在修改,增加主键约束
create table stu(id int , name varchar(25));

alter table stu modify id int primary key ;

# 如果还想增加自增长,那么还可以继续修改
alter table stu modify id int auto_increment;
  • 唯一约束:unique 主键的值 也是唯一的。

唯一约束指的是表示某个列的值唯一不允许重复。

# 可以在建表的时候给出
create table stu(id int primary key auto_increment , name varchar(25) unique);

# 或者后面再修改
create table stu(id int primary key auto_increment , name varchar(25));

alter table stu modify name varchar(25) unique;

  • 非空约束:not null

非空约束,指的是具体某一列不允许为空,必须有值。

# 可以在建表的时候给出
create table stu(id int primary key auto_increment , name varchar(25) not null);

# 或者后面再修改
create table stu(id int primary key auto_increment , name varchar(25));

alter table stu modify name varchar(25) not null;

7. 表记录CRUD

该小节注重的是表中数据的操作。

1. 增加

--添加一条记录,对具体某些列赋值。顺序要对应 ,若是字符或者日期需要添加 '' 引号
insert into(列名1,列名2,列名3..) values  (1,2,3..); 

	
--添加一条记录,表中的所有列都要赋值。	
insert intovalues (1,2,3..); 

2. 删除

-- 删除的命令和上面删除表的命令非常相似。 只是多了where条件而已。
delete from 表名 [where 条件];

3. 修改

-- 修改表,针对具体某一列进行赋值
update 表名 set 字段名=,字段名=[where 条件];

-- 如: 更新张三的年龄 ,后面的where 用于限定找到张三
update student set age = 18 where name = '张三';

--如果后面不带where, 那么将会把整张表的所有学生年龄都改为18
update student set age = 18;

4. 查询

  • 准备表中数据
-- 准备一张商品分类表(分类ID,分类名称,分类描述)
create table category(
	cid int primary key auto_increment,
  	cname varchar(10),
  	cdesc varchar(50)
);

-- 准备一张商品表(商品编号,商品名称,商品价格,商品描述,商品分类编号)
create table product(
	pid int primary key auto_increment,
  	pname varchar(10),
  	price double,
  	pdesc varchar(50),
  	cno   int
);

-- 数据的准备
insert into category values(null,'手机数码','黑马生产的小手机');
insert into category values(null,'鞋靴箱包','传智生产的包包');
insert into category values(null,'香烟酒水','黄鹤楼,茅台');
insert into category values(null,'馋嘴零食','卫龙辣条,周黑鸭');

insert into product values(null,'锤子',2999,'可以砸榴莲的手机',1);
insert into product values(null,'小米',1599,'为发烧而生',1);
insert into product values(null,'李宁',99,'不走寻常路',2);
insert into product values(null,'耐克',399,'just do it',2);
insert into product values(null,'黄鹤楼',20,'饭后一根烟,胜做活神仙',3);
insert into product values(null,'卫龙辣条',5,'卫龙辣条加料不加价',4);
insert into product values(null,'老干妈辣椒酱',9,'永远不变的味道',4);
insert into product values(null,'老干爹辣椒酱',19,'永远不变的味道',4);
insert into product values(null,'黄鹤楼',20,'饭后一根烟,胜做活神仙',3);
  • 简单查询
-- 语法如下: 
select [distinct]*[列名,列名] from[where 条件].

-- 例子: 
* 1.查询所有的商品.	select * from product;
* 2.查询商品名和商品价格.	select pname,price from product;
* 3.别名查询.使用的关键字是as.as可以省略的.	 
    * 3.1表别名:	select * from product as p;
    * 3.2列别名:select pname as pn from product;	
* 4.去掉重复值.	select distinct price from product;
  • 条件查询
* 1.查询商品名称为十三香的商品所有信息:
    * select * from product where pname = '十三香';
* 2.查询商品价格>60元的所有的商品信息:
    * select * from product where price > 60;

	-- where后的条件写法:
    * 比较运算符:> ,<,=,>=,<=,<>
    * 逻辑运算符: 与或非
    
    * is null		: 专门用于判断是否为空的
    * is not null	: 专门用于判断是否不为空的
    * like 模糊查询中
    			 _  : 代表一个字符 
    			 %	: 代表任意个数字符. 
    	-- 查询商品名称中带有 新 的商品信息		 
        * select * from product where pname like '%新%';
    * in 在某个范围中获得值.
        * select * from product where pid in (2,5,8);
    * between 12 and 56
  
  • 排序查询
* 1.查询所有的商品,按价格进行排序.(asc-升序,desc-降序)
    * select * from product order by price;
* 2.查询名称有新的商品的信息并且按价格降序排序.
    * select * from product where pname like '%新%' order by price desc;
    
 按价格排序 、 分数排序 、 日期 、 年龄...
 
 	order byasc(升序) | desc(降序)

  • 聚合查询
* sum(),avg(),max(),min(),count();
* 1.获得所有商品的价格的总和.--select sum(price) from product;
* 2.获得所有商品的平均价格.--select avg(price) from product;
* 3.获得所有商品的个数.--select count(*) from product;
  • 分组查询
* 1.根据cno字段分组,分组后统计商品的个数.
    * select cno,count(*) from product group by cno;
    
* 2.根据cno分组,分组统计每组商品的平均价格,并且平均价格> 60;
    * select cno,avg(price) from product group by cno having avg(price)>60;

	having 关键字可以让我们筛选成组后的各种数据,可以理解为对分组后的数据进行再次过滤
  • 分页查询
-- 第一个?表示跳过前面多少条 , 第二个?表示返回多少条记录。
select * from product limit ? , ? ; 

查询语句的完整模板:

select 列名 from 表名 where 条件 group by 分组的条件 having 分组之后的条件 order by 排序的条件 limit 起始索引,几条数据;

学习目标

  • 完成对MYSQL数据库的多表查询及建表的操作
  • 掌握MYSQL中多表的创建及多表的查询
  • 掌握MYSQL中的表关系分析并能正确建表
    • 掌握子查询的使用

SQL 创建多表及多表之间关系

需求

分类表和商品表之间是不是有关系? 如果有关系,在数据库中如何表示这种关系

--创建一个新的数据库 day25
create database day25;
use day25;
--创建分类表 cid,cname,cdesc
create table category(
	cid int primary key auto_increment,
  	cname varchar(20),
  	cdesc varchar(50)
);

insert into category values(null,'手机数码','黑马生产的小手机');
--创建商品表 pid,pname,price,pdesc,cno
create table product(
	pid int primary key auto_increment,
  	pname varchar(20),
  	price double,
  	pdesc varchar(50),
  	cno int
);
insert into product values(null,'锤子',2999,'可以开核桃的',11);

-- 外键约束 foreign key
-- 主要是用来约束从表中记录,必须是参考主表的记录
从表: product
主表: category

-- 添加外键约束,添加到从表中
update product set cno=1 where pid=1;
alter table product add foreign key(cno) references category(cid);
-- 添加外加约束之后,无法删除,要想删除得先删除商品表中对应的cno
delete from category where cid=1;

-- 五大约束:
	主键约束: primary key  非空并且唯一
	唯一约束: unique  唯一可以为空
	非空约束: not null 不能为空
	检查约束: check(条件) mysql直接忽略检查约束

	外键约束: foreign key 约束从表中的记录必须参考主表

技术分析

  • 多表之间的关系如何来维护

    外键约束: foreign key

    • 插入数据: 数据必须先存在于主表,然后再插入从表中的数据
    • 删除数据(删主表时): 必须先删除从表中数据,再删除主表中的数据
  • 多表之间的建表原则

    • 一对多: 学生和班级, 商品分类和商品
      • 建表原则: 在多的一方添加一个键,然后让它作为外键指向一的一方
    • 多对多: 学生和选课
      • 建表原则:创建一张中间表,将多对多的关系,拆分成一对多的关系, 中间表至少要包含两个外键,这两个外键分别指向各自原来的表
    • 一对一: 公民和身份证号,公司和公司地址
      • 建表原则:
        1. 将两张表的主键建立连接,
        2. 将两张合并成一张表
        3. 将一对一的关系,拆分成****一对多的关系,在任意一方添加一个外键约束**,并且还要一个唯一约束****

商城表实例的分析

按照用户的购物流程进行分析

  • 用户表
  • 订单表
  • 商品表
  • 商品分类表
-- 用户表 (用户的ID,用户名,密码,手机)
create table user(
  	uid int primary key auto_increment,
	name varchar(10),
	password varchar(20),
	mobile varchar(11)
  );
  
-- 订单表 (订单编号,总价,订单时间 外键-->用户的ID)
create table orders(
  	oid int primary key auto_increment,
	total double,
	otime timestamp,
	uno int,
	foreign key(uno) references user(uid)
);
  
-- 商品分类表(分类ID,分类名称,分类描述)
create table category(
 	cid int primary key auto_increment,
	cname varchar(20),
	cdesc varchar(50)
);

-- 商品表 (商品ID, 商品名称,商品价格,商品描述,外键cno)
create table product(
	pid int primary key auto_increment,
	pname varchar(10),
	price double,
	pdesc varchar(50),
 	cno int,
 	foreign key(cno) references category(cid)
);

--  订单项: 中间表(订单ID,商品ID,商品数量,订单项总价)
  create table orderitem(
  	ono int,
	pno int,
	num int,
	subtotal double,
  	foreign key(ono) references orders(oid),
	foreign key(pno) references product(pid)
  );
  
-- 准备数据: 假设张三用户注册
insert into user values(1,'zs','123','110');

-- 准备数据: 插入分类表的数据
insert into category values(1,'手机数码','黑马生产的小手机');
insert into category values(2,'鞋靴箱包','传智生产的包包');
insert into category values(3,'香烟酒水','黄鹤楼,茅台');
insert into category values(4,'馋嘴零食','卫龙辣条,周黑鸭');
insert into category values(5,'电脑办公','联想电脑外星人');

-- 准备数据 : 插入商品表的数据
insert into product values(1,'锤子',2999,'可以砸榴莲的手机',1);
insert into product values(2,'小米',1599,'为发烧而生',1);
insert into product values(3,'李宁',99,'不走寻常路',2);
insert into product values(4,'耐克',399,'just do it',2);
insert into product values(5,'黄鹤楼',20,'饭后一根烟',3);
insert into product values(6,'黄鹤楼',20,'饭后一根烟',3);
insert into product values(7,'卫龙辣条',5,'卫龙辣条加料不加价',4);
insert into product values(8,'老干妈辣椒酱',9,'永远不变的味道',4);
insert into product values(9,'老干娘辣椒酱',null,'永远不变的味道',4);
insert into product values(10,'热干面',10,'大武汉热干面',null);

-- 准备数据: 假设张三在我们的商城下两个订单
 -- zs买东西: 
 -- 1号订单:
  	-- 锤子: 1  10  29990
  	-- 李宁: 3  2	198
-- -- 向 订单表 插入1号订单信息(订单编号,订单总价,订单时间,用户编号)  	
insert into orders values(1,30000,null,1);
-- -- 向 订单项表 插入1号订单包含的商品信息(订单编号,商品编号,商品数量,商品小计)
insert into orderitem values(1,1,10,29990);
insert into orderitem values(1,3,2,198);

 -- 2号订单:
  	-- 卫龙辣条: 7  10 50
  	-- 老干妈辣椒酱:8 2 18
  	-- 李宁: 3  1	99 
-- -- 向 订单表 插入2号订单信息(订单编号,订单总价,订单时间,用户编号)  	  	
insert into orders values(2,150,null,1);
-- -- 向 订单项表 插入2号订单所包含的商品信息(订单编号,商品编号,商品数量,商品小计)
insert into orderitem values(2,7,10,50);
insert into orderitem values(2,8,2,18);
insert into orderitem values(2,3,1,99);

商城表多表查询

多表查询

  • 交叉连接查询 笛卡尔积 : 两张表的乘积,查询的结果没有实际意义

  • 内连接查询:

    隐式内连接: select * from product p,category c where p.cno = c.cid;

    显式内连接: select * from product p inner join category c on p.cno = c.cid;

  • 外连接查询:

  • 左外连接: 以左表为基础,将左表中所有的记录都查询出来,如果没有对应的记录,用null值填充

    Select * from product p left outer join category c on p.cno = c.cid;

  • 右外连接:以右表为基础,将右表中的所有记录都查询出来,如果没有对应的记录,用null值填充

    select * from product p right outer join category c on p.cno= c.cid;

多表查询练习

查询出商品名称,商品分类名称信息

select p.pname,c.cname from product p left outer join category c on p.cno = c.cid;

查询分类名称为手机数码的所有商品信息

select * from product p left outer join category c on p.cno = c.cid;
select * from product p left outer join category c on p.cno = c.cid where c.cname='手机数码';

按照商品分类的名称统计商品的个数:

 select c.cname,COUNT(*) from product p left outer join category c on p.cno = c.cid group by c.cname;

-- 按照商品分类的编号统计商品的个数
select cno,count(*) from product group by cno;

查询1号订单的订单项信息(orderitem)对应的商品信息(product)

select * from orderitem oi,product p where oi.pno = p.pid and oi.ono=1;

多表及子查询数据

  • 员工信息表
-- 员工信息表 employee
CREATE TABLE emp(
	empno int comment '员工编号',
	ename varchar(50) comment '员工姓名',
	job varchar(50) comment '员工工作',
	mgr int comment '员工经理编号',
	hiredate date comment '员工入职日期',
	sal decimal(7,2) comment '员工工资', 
	comm decimal(7,2) comment '员工奖金',
	deptno int comment '员工所处部门'
);

INSERT INTO emp values(7369,'SMITH','CLERK',7902,'1980-12-17',800,NULL,20);
INSERT INTO emp values(7499,'ALLEN','SALESMAN',7698,'1981-02-20',1600,300,30);
INSERT INTO emp values(7521,'WARD','SALESMAN',7698,'1981-02-22',1250,500,30);
INSERT INTO emp values(7566,'JONES','MANAGER',7839,'1981-04-02',2975,NULL,20);
INSERT INTO emp values(7654,'MARTIN','SALESMAN',7698,'1981-09-28',1250,1400,30);
INSERT INTO emp values(7698,'BLAKE','MANAGER',7839,'1981-05-01',2850,NULL,30);
INSERT INTO emp values(7782,'CLARK','MANAGER',7839,'1981-06-09',2450,NULL,10);
INSERT INTO emp values(7788,'SCOTT','ANALYST',7566,'1987-04-19',3000,NULL,20);
INSERT INTO emp values(7839,'KING','PRESIDENT',NULL,'1981-11-17',5000,NULL,10);
INSERT INTO emp values(7844,'TURNER','SALESMAN',7698,'1981-09-08',1500,0,30);
INSERT INTO emp values(7876,'ADAMS','CLERK',7788,'1987-05-23',1100,NULL,20);
INSERT INTO emp values(7900,'JAMES','CLERK',7698,'1981-12-03',950,NULL,30);
INSERT INTO emp values(7902,'FORD','ANALYST',7566,'1981-12-03',3000,NULL,20);
INSERT INTO emp values(7934,'MILLER','CLERK',7782,'1982-01-23',1300,NULL,10);
INSERT INTO emp values(7981,'MILLER2','CLERK',7788,'1992-01-23',2600,500,20);
  • 部门信息表
-- 部门表
CREATE TABLE dept(
	deptno int comment '部门编号',
	dname varchar(14) comment '部门的名称', 	
	loc varchar(13) comment '部门所处的位置'
);

INSERT INTO dept values(10, 'ACCOUNTING', 'NEW YORK');
INSERT INTO dept values(20, 'RESEARCH', 'DALLAS');
INSERT INTO dept values(30, 'SALES', 'CHICAGO');
INSERT INTO dept values(40, 'OPERATIONS', 'BOSTON');
  • 基本查询
-- 所有员工的信息
-- 薪资大于等于1000并且小于等于2000的员工信息
-- 从员工表中查询出所有的部门编号
-- 查询出名字以A开头的员工的信息
-- 查询出名字第二个字母是L的员工信息
-- 查询出没有奖金的员工信息
-- 所有员工的平均工资
-- 所有员工的工资总和
-- 所有员工的数量
-- 最高工资
-- 最少工资
-- 所有员工的信息
SELECT * FROM emp e LEFT JOIN dept d ON e.deptno=d.deptno;
-- 薪资大于等于1000并且小于等于2000的员工信息
SELECT * FROM emp e LEFT JOIN dept d ON e.deptno=d.deptno WHERE e.sal>=1000 AND e.sal<=2000;
-- 从员工表中查询出所有的部门编号
SELECT DISTINCT e.deptno FROM emp e;
-- 查询出名字以A开头的员工的信息
SELECT * FROM emp e LEFT JOIN dept d ON e.deptno=d.deptno WHERE e.ename LIKE 'A%';
-- 查询出名字第二个字母是L的员工信息
SELECT * FROM emp e LEFT JOIN dept d ON e.deptno=d.deptno WHERE e.ename LIKE '_L%';
-- 查询出没有奖金的员工信息
SELECT * FROM emp e LEFT JOIN dept d ON e.deptno=d.deptno WHERE e.comm IS NULL;
-- 所有员工的工资总和
SELECT SUM(sal) FROM emp e ;
-- 所有员工的数量
SELECT COUNT(*) FROM emp e ;
-- 最高工资
SELECT MAX(sal) FROM emp e ;
-- 最少工资
SELECT MIN(sal) FROM emp e ;
  • 分组查询
-- 每个部门的平均工资
SELECT deptno,AVG(sal) FROM emp GROUP BY(deptno);
  • 多表查询
-- 查询员工编号,员工姓名,经理编号,经理姓名
SELECT e.empno,e.ename,e.mgr,m.ename AS mename FROM emp e,emp m WHERE e.mgr=m.empno;
  • 子查询
-- 单行子查询(> < >= <= = <>)
	-- 查询出高于10号部门的平均工资的员工信息
	SELECT * FROM emp WHERE sal>(SELECT AVG(sal) FROM emp);
	
-- 多行子查询(in  not in any all)    >any  >all
	-- 查询出比20号部门任何员工薪资高的员工信息
	SELECT * FROM emp e WHERE sal>(SELECT MAX(sal) FROM emp e WHERE e.deptno=20);


-- Select接子查询
	-- 获取员工的名字和部门的名字
	SELECT e.ename,d.dname FROM emp e,dept d WHERE e.deptno=d.deptno;

-- from后面接子查询
	-- 查询emp表中经理信息
	SELECT * FROM emp e WHERE e.empno IN (SELECT DISTINCT mgr FROM emp e);
	
-- where 接子查询
	-- 薪资高于10号部门平均工资的所有员工信息
	SELECT * FROM emp e WHERE sal>(SELECT AVG(sal) FROM emp e WHERE deptno=10);
-- having后面接子查询
	-- 有哪些部门的平均工资高于30号部门的平均工资
	SELECT deptno FROM emp e GROUP BY deptno HAVING AVG(sal)>(SELECT AVG(sal) FROM emp e WHERE e.deptno=30);

-- exists的用法
   -- 查询所有有员工的部门信息

-- 最高工资的员工信息
SELECT * FROM emp e WHERE sal=(SELECT MAX(sal) FROM emp e);
-- 最低工资的员工信息
SELECT * FROM emp e WHERE sal=(SELECT MIN(sal) FROM emp e);
-- 工资>JONES工资
SELECT * FROM emp e WHERE sal>(SELECT sal FROM emp e WHERE ename='JONES');
-- 查询与SCOTT同一个部门的员工
 SELECT e.ename FROM emp e WHERE e.deptno=(SELECT e.deptno FROM emp e WHERE e.ename='SCOTT');
-- 工资高于30号部门所有人的员工信息
   SELECT * FROM emp e WHERE sal>ALL( SELECT sal FROM emp e WHERE e.deptno=30);
-- 查询工作和工资与MARTIN完全相同的员工信息
ELECT * FROM emp e WHERE e.job=(SELECT job FROM emp e WHERE e.ename='MARTIN') AND e.sal=(SELECT sal FROM emp e WHERE e.ename='MARTIN') AND e.ename='MARTIN';
-- 有两个以上直接下属的员工信息
SELECT * FROM emp e WHERE e.empno IN (SELECT mgr FROM emp e GROUP BY mgr HAVING COUNT(mgr)>2);
-- 查询员工编号为7788的员工名称,员工工资,部门名称,部门地址
SELECT DISTINCT e.ename,e.sal,d.dname,d.loc FROM emp e,dept d WHERE e.empno=7788 AND e.deptno=d.deptno;
-- 查询薪资大于薪资最高的员工所在部门的平均工资和薪资最低的员工所在部门的平均工资的平均工资的员工信息

-- 查询出高于本部门平均工资的员工信息 
SELECT * FROM emp e1 ,(SELECT deptno,AVG(sal) avgsal FROM emp GROUP BY deptno) e2 WHERE e1.deptno=e2.deptno AND e1.sal>e2.avgsal;

-- 列出达拉斯加工作的人中,比纽约平均工资高的人
emp e 
WHERE e.deptno=(SELECT d.deptno FROM dept d WHERE d.loc='DALLAS') 
AND 
e.sal>(SELECT AVG(sal) FROM emp e,dept d WHERE e.deptno=d.deptno AND d.loc='NEW YORK');
-- 查询7369员工编号,姓名,经理编号和经理姓名
SELECT e1.empno,e1.ename,e2.empno,e2.ename FROM emp e1,emp e2 WHERE e1.mgr=e2.empno AND e1.empno=7369;
-- 查询出各个部门薪水最高的员工所有信息
SELECT * FROM emp e ,(SELECT MAX(sal) maxsal,e.deptno FROM emp e GROUP BY e.deptno) c WHERE e.deptno=c.deptno AND e.sal=c.maxsal;

面试题

CREATE TABLE test(
  name CHAR(20),
  kecheng CHAR(20),
  fenshu CHAR(20)
);
INSERT INTO test VALUES('张三','语文',81),
('张三','数学',75),
('李四','语文',76),
('李四','数学',90),
('王五','语文',81),
('王五','数学',82);

--请用一条Sql语句查处每门分数都大于80的学生

SELECT t.name,MIN(fenshu) FROM test t GROUP BY t.name HAVING MIN(fenshu)>80;

视图

为什么需要视图

假设我们现在想要获取这样的一个结果:

​ 我想查询 员工编号, 员工姓名, 员工的经理编号, 经理的姓名

显示结果如下:

python正则表达式和数据库_第4张图片
要想得到这样一个结果,我们需要编写的语句是这样的:

select e.empno ,e.ename ,e.mgr ,m.ename 
from emp e,emp m 
where e.mgr = m.empno;	

我们可以看到,这样一条语句非常的复杂,而且很长, 试想一下,假设我们要在很多地方都要用到它, 我们能不能对它进行封装呢?

这里我们就可以考虑使用视图啦!

视图介绍

  1. 视图其实就是将一条复杂的SQL查询语句封装成一张虚表!
  2. 视图本身不存储任何数据,所有的数据都存放在原来的表中, 可以把视图看做是逻辑上的一张表
  3. 当原始表中的数据,发生改变的时候, 视图查询出来的结果也会跟着发生变化

例如: 我们可以将上面复杂的查询语句,封装成一个名称为: v_test 的视图.

假设现在我还想得到上面的结果,那么我只需要从视图中查询就好啦!

select * from v_test;
-- 注意: from 后面我们写的是视图的名称

好啦! 关于视图,我们就先简单介绍到这里啦! 下面我们来介绍如何使用视图

创建视图

我们首先给大家介绍一下视图创建的语法,它有点类似我们之前创建数据库或者创建表的语法:

create view 视图的名称  as 查询语句;

在这里我们需要注意:

  1. 视图中的字段名称不能有重复的喔!
  2. 视图的名称最好以 v_ 开头

例如我们创建一个上面的视图:

create view v_test 
as 
select e.empno ,e.ename ,e.mgr ,m.ename mname
from emp e,emp m 
where e.mgr = m.empno;	

这样,我们就创建好啦一个视图啦!

查看视图

我们如何去查看我们这个数据库中有哪些视图呢?

这里给大家介绍一条命令!

show tables;  -- 没错, 就是它, 它不仅能列出所有的表,还能列出所有的视图呢!

使用视图

我们已经创建了v_test,那我们如何去使用它呢?

还记得我们前面所介绍的吗? 视图其实是一张虚表, 我们可以和查看表一样来查看视图

select * from v_test;

根据条件查询

select * from v_test where empno>7788;

试一试: 我们尝试修改原始表,来查看一下视图中的变化!

删除视图

这个操作和我们删除数据库和删除表是类似的,我们只需要执行如下命令即可:

drop view 视图的名称
例如:
drop view v_test; -- 它会将我们之前创建的视图删除掉

小结

  1. 视图可以将复杂的查询结果,在逻辑上封装成一张虚表
  2. 我们可以通过select * from 视图的方式快速获取到视图的内容
  3. 视图本身并不存储任何数据,它只是逻辑上是一张表,所有的数据都存放在原来的表中
  4. 通过视图,我们还能屏蔽真实的表名和一些字段,从而更加安全

事务

什么是事务

事务,就是要完成的某件事情,例如网上购物,转账,做饭,洗澡等等!

为什么需要事务

在我们日常的开发过程中,我们想要完成某个功能时,可能需要执行很多条SQL语句, 如果这些SQL执行到一半,突然停电啦. 那么就会导致这个功能只完成啦一半,这种情况能允许它出现吗 ?

例如: 我们以张三给王五 银行转账500块钱为例

  1. 从 张三 的余额中 减去500块钱
  2. 向 王五 的余额中 增加500块钱

这里面看起来就是两条很简单的sql语句呀!

update 银行用户表 set 余额=余额 - 500 where 姓名=张三;
update 银行用户表 set 余额=余额 + 500 where 姓名=王五;

如果按照正常流程,那么这里面就没有问题!

倘若第一条语句执行成功之后,系统突然奔溃了怎么办呢? 那张三的账户少了500块钱, 王五的账户并没有增加500块钱, 那张三的钱就不翼而飞啦!

很显然,这种情况不应该存在!

正确的方式应该是:

​ 张三账户扣500块钱

​ 王五账户加500块钱

这两个操作要么都成功,要么都失败!

事务其实就是一些列的SQL操作,要么都成功,要么都失败! 不允许部分执行成功,部分执行失败的情况发生

事务入门

准备数据

create database day26;

use day26;
create table user(
	id int primary key auto_increment,
    name varchar(20),
    money double
);

insert into user values(null,'jack',2000);
insert into user values(null,'rose',2000);

命令行演示

-- 显示有关提交的变量信息
show variables like '%commit%';

-- 默认的情况下:每一条SQL语句其实就是一个事务
1.开启事务
2.执行语句:update user set money=3000;
3.提交事务

-- 关闭自动提交
set autocommit = off;  或者写成  set autocommit = 0; 

-- 开启事务 
start transaction;
-- 执行操作,数据库中数据并没有被修改
update user set money=money-500 where name='jack'; 

-- 必须commit提交或者rollback回滚才能结束事务
commit;

事务特性ACID

  • 原子性(Atomicity)
  • 一致性(Consistency)
  • 隔离性(Isolation)
  • 持久性(Durability)
原子性

一个事务必须被视为一个不可分割的最小工作单元,整个事务中的所有操作要么全部提交成功,要么全部失败回滚,对于一个事务来说,不可能只执行其中的一部分操作,这就是事务的原子性

一致性

数据库总是从一个一致性的状态转换到另一个一致性的状态。

隔离性

通常来说,一个事务的执行,不受其他事务的影响

持久性

事务一旦提交,则其所做的修改会永久保存到数据库。(此时即使系统崩溃,修改的数据也不会丢失。)

事务隔离级别

主要是用来解决事务并发执行,引发的问题。

如果两个事务同时,或者交错执行,那么他们的执行结果可能会受对方影响,这会导致数据的前后显示不一致。所以为了保证并发操作数据的正确性及一致性,SQL规范于1992年提出了数据库事务隔离级别

事务的并发主要有两个方面的问题 : 读的问题 | 写的问题 , 相对于写的问题,读的问题出现的几率更高些。

安全隐患

如果事务没有任何隔离设置,那么在并发情况会出现以下问题:

  • 脏读

脏读: 指 一个事务 读到了另一个事务还未提交的数据

  • 不可重复读

一个事务读到了另一个事务提交的更新的数据, 导致多次查询结果不一致。(针对update)

  • 虚读|幻读

一个事务读到了另一个事务已提交的插入的数据,导致多次查询结果不一致。(针对 insert)

隔离级别

a. 读未提交

​ read uncommitted

  1. 打开两个dos终端, 设置A窗口的隔离级别为 读未提交

    将数据库的隔离级别设为read uncommitted
    	set session transaction isolation level read uncommitted;
    查看隔离级别
    	select @@tx_isolation;
    
  2. 两个窗口都分别开启事务

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hzj7ZWN6-1581258609015)(./img/tx_01.png)]

读未提交: 一个事务可以读取到另一个事务没有提交的数据

出现的问题: 脏读、不可重复读、虚读

b. 读已提交

​ read committed

  1. 设置A窗口的隔离级别为 读已提交

    将数据库的隔离级别设为read committed
    set session transaction isolation level read committed;
    
  2. A B 两个窗口都开启事务, 在B窗口执行更新操作。

  3. 在A窗口执行的查询结果不一致。 一次是在B窗口提交事务之前,一次是在B窗口提交事务之后。

python正则表达式和数据库_第5张图片

读已提交:一个事务能读取到另一个事务已经提交的数据,但是未提交的数据读取不到了。

避免: 脏读

出现的问题: 不可重复 , 虚读

c. 可重复读

Repeatable Read: set session transaction isolation level repeatable read;

避免: 脏读 、不可重复读

出现的问题: 虚读(但是其实mysql已经在底层把这个问题给避免了。)

d. 串行化

serializable: set session transaction isolation level serializable;

避免: 脏读, 不可重复, 虚读

出现的问题: 不会出现问题, 因为一个在执行的时候,其它事务处于等待状态

  • 按功能大小 排序 : 序列化 > 可重复读 > 读已提交 > 读未提交
  • 按效率来排序: 序列化 < 可重复读 < 读已提交 < 读未提交

MySql: 默认隔离级别: 可重复读 . 通常数据给我们设定的默认隔离级别都是最优的一种级别! 我们一般不会去修改它!

示例代码

演示(了解)	: 开启两个窗口, 在两个窗口中设置隔离级别		
	update account set money =520 where name = 'jack';

	演示脏读的发生
		将数据库的隔离级别设为read uncommitted
			set session transaction isolation level read uncommitted;
		查看隔离级别
			select @@tx_isolation;
			
	解决脏读
		将数据库的隔离级别设为read committed
			set session transaction isolation level read committed;
		不能避免不可重复读和幻读的发生
		
	解决不可重复读:
		将数据库的隔离级别设为repeatable read	
			set session transaction isolation level repeatable read;
		
	演示串行化
		将数据库的隔离级别设为serializable	
			set session transaction isolation level serializable;

索引

什么是索引

  • 索引是一种排好序的快速查找的数据结构,它帮助数据库高效的查询数据

  • 在数据之外,数据库系统还维护着满足特定查找算法的数据结构,这些数据结构以某种方式指向数据,这样就可以在这些数据结构上实现高效的查找算法.这种数据结构,就是索引

python正则表达式和数据库_第6张图片

  • 一般来说索引本身也很大,不可能全部存储在内存中,因此往往以索引文件的形式存放在磁盘中

  • 我们平常所说的索引,如果没有特别说明都是指BTree索引

索引优缺点

  • 优点:

    • 提高数据查询的效率,降低数据库的IO成本
    • 通过索引对数据进行排序,降低数据排序的成本,降低CPU的消耗
  • 缺点:

    • 索引本身也是一张表,该表保存了主键与索引字段,并指向实体表的记录,所以索引列也要占用空间

    • 虽然索引大大提高了查询的速度,同时反向影响增删改操作的效率,因为表中数据变化之后,会导致索引内

      容不准,所以也需要更新索引表信息,增加了数据库的工作量

    • 随着业务的不断变化,之前建立的索引可能不能满足查询需求,需要消耗我们的时间去更新索引

索引的使用

查看索引

查看数据库中已有索引

show index from 表名;

创建索引

  • 如果指定字段是字符串,需要指定长度,长度最好与定义字段时一致
  • 字段类型如果不是字符串,可以不填写长度
create index 索引名称 on 表名(字段名(长度));

删除索引

drop index 索引名称 on 表名;

验证索引

索引在数据量小的表中是体现不出来它的作用的,只有当表中数据非常庞大的时候,才能体现出索引的重要性!

为此,我们首先插入5000000条记录到数据库表中.

import pymysql
import random

conn = pymysql.connect(host="localhost",port=3306,user="root",password="123456")

# 创建执行SQL的游标对象
cursor = conn.cursor()
# 创建数据库
cursor.execute("create database if not exists test_index");
# 选中数据库
cursor.execute("use test_index")
# 执行建表语句
cursor.execute("create table if not exists  emp(id int primary key,name varchar(10),age int,sal double )")

# 插入500万条记录
for i in range(5000000):
    # 随机参数
    name = "n"+str(i)
    age = random.randrange(1,100)
    sal = random.randrange(1000,5000)
    cursor.execute("insert into emp values(%s,%s,%s,%s)",args=[i,name,age,sal])

# 提交事务
conn.commit()
# 关闭连接
conn.close()

除了使用上面这种方式导入外,mysql还提供了换门用于数据快速导入的功能

-- 创建一个数据库
create database heima;
use heima;
-- 创建一张测试表
create table tsmall(
    id int primary key auto_increment,
    name varchar(20),
    age int,
    sal int
);
create table tbig(
    id int primary key auto_increment,
    name varchar(20),
    age int,
    sal int
);
-- 将文件中的数据导入的语法
load data local infile '文件路径' replace into table 表名 fields terminated by '字段分隔符'

-- 导入数据文件中的数据
load data local infile 'd:\small.txt' replace into table tsmall fields terminated by ',';
load data local infile 'd:\large.txt' replace into table  tbig fields terminated by ',';

查询验证

MySQL 的 Query Profiler 是一个使用非常方便的 Query 诊断分析工具,通过该工具可以获取一条Query 在整个执行过程中多种资源的消耗情况,如 CPU,IO,SWAP 等同时还能得到该 Query 执行过程中 MySQL 所调用的各个函数在源文件中的位置。

通过执行 “set profiling”命令,可以开启关闭 Query Profiler 功能。

  • 开启运行时间监测:
set profiling=1;
  • 查询名字为n4000000的用户信息
select * from emp where name='n4000000'
  • 查看执行时间

通过执行show profile命令获取当前系统中保存的多个Query的profile的概要信息

show profiles;
  • 为name列创建索引
create index name_emp on test_index(name(10))

  • 再次执行前面的语句
select * from emp where name='n4000000'
  • 再次查看执行时间
show profiles;

小结

  • 索引是一种已经排好序的数据结构
  • 它能帮助我们提高数据库查询的效率
  • 创建索引: create index 索引名 on 表名(字段(长度))
  • 查看索引: show index from 表名

数据库设计三范式

研发人员在对数据库长期的使用和研究中做出了一些总结, 并对数据库的设计提出了一些规范. 这些规范被称为: 范式(Normal Form)

第一范式

概念: 强调列的原子性,即列不能再拆分

例如: 我们想设计一张联系人表,表中应该含有:姓名,电话号码,地址等信息

我们按照如下这种方式来设计是否合理呢?

在这里插入图片描述

经过仔细的分析,我们发现这张表里面的contact字段设计不太合理. 假设我们想去更新里面的电话号码会很麻烦! 并且它不满足我们刚才介绍的第一范式

第一范式强调列不能再拆分,为了解决这个问题,我们可以这样重新设计联系人表!

在这里插入图片描述

现在我们的表是不是更加合理啦!

第二范式

在满足1NF的前提下, 表必须拥有主键列, 非主键字段必须完全依赖于主键列 ,而不能只依赖主键的一部分!

我们来看下下面这张表,这张表叫做订单详情表,其中orderid订单编号,productID 商品的编号,UnitPrice单价,Discount折扣,Count购买数量,ProductName商品名称

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gnen5E3a-1581258609018)(./img/2nf.jpg)]

我们大致一看,这张表似乎设计的没有问题啊! 那么我们如何才能唯一的确定一行记录呢 ?

很显然,在当前案例中,只有**(OrderID和ProductID)组合在一起才能唯一确定一行记录, 像这种主键由多列构成的, 我们可以称它为联合主键**

下面我们再来看我们的表中数据, 同样一款商品霸王洗发水UnitPrice和ProductName在表中出现了多次,并且这两个信息完全依赖于ProductID,

而Discount和Count则是完全依赖于主键(OrderID,ProductID)

由于UnitPrice和ProductName没有完全依赖于主键(OrderID,ProductID),所以它不满足第二范式

那么我们应该如何让我们上面的表满足第二范式呢? 这里我们要进行拆表操作啦! 将原本一张表中的数据,拆到两张表中!

如下所示:

python正则表达式和数据库_第7张图片

第三范式

满足2NF的前提下, 非主键列必须完全依赖主键列,不能存在非主键列A依赖非主键列B, 非主键列B依赖于主键列的情况,即不能存在传递依赖!

第三范式和第二范式非常容易搞混淆,我们还是以实际案例的方式来演示吧!

首先,我们来看一下下面这张表

在这里插入图片描述

当前Order表中

  1. 主键列: OrderId
  2. 非主键列: OrderDate订单日期,UserID用户编号,UserName用户名,UserAddr用户地址

在当前表中,出现了一种情况就是UserName依赖于UserID,而UserID又依赖于OrderId,即出现了传递依赖的情况

那么我们如何才能解决上面的问题呢? 大家可能已经想到了,我们可以进行拆表

在这里插入图片描述

三范式总结

  1. 所谓的范式,其实就是我们设计数据库时应该遵守的一种规范
  2. 第一范式: 强调列应该是最小单元,不能再分
  3. 第二范式: 强调必须要有主键,并且非主键列必须完全依赖主键列,不能出现部分依赖!
  4. 第三范式: 强调非主键列必须完全依赖主键列,不能出现传递依赖的情况!

练一练: 请按照三范式设计如下的表,并且描述表与表之间的关系

  1. 商品表
  2. 商品分类表
  3. 商品品牌表
  4. 订单表
  5. 用户表

需要注意还需要额外的一些表吗?

python正则表达式和数据库_第8张图片

账户管理(一)

1.MySQL账户管理

  • 在我们之前登录MySQL的时候我们都是直接使用的root用户,root用户属于数据库系统中的超级管理员,有权限对mysql进行任何想要做的操作。
  • 如果在生产环境下操作数据库时也是全部直接使用root账户连接,这就和悬崖边跳舞差不多。所以 创建特定的账户,授予这个账户特定的操作权限,然后连接进行操作 比如常规的crud 才是正道。
  • MySQL账户体系:根据账户所具有的权限的不同,MySQL的账户可以分为以下几种
    • 服务实例级账号:,启动了一个mysqld,即为一个数据库实例;如果某用户如root,拥有服务实例级分配的权限,那么该账号就可以删除所有的数据库、连同这些库中的表
    • 数据库级别账号:对特定数据库执行增删改查的所有操作
    • 数据表级别账号:对特定表执行增删改查等所有操作
    • 字段级别的权限:对某些表的特定字段进行操作
    • 存储程序级别的账号:对存储程序进行增删改查的操作

注意:进行账户操作时,需要使用root账户登录,这个账户拥有最高的实例级权限。账户的操作主要包括创建账户、删除账户、修改密码、授权权限等。

需要使用实例级账户登录后操作,以root为例

主要操作包括:

  • 查看所有用户
  • 修改密码
  • 删除用户

2. 查看所有用户

  • 所有用户及权限信息存储在mysql数据库的user表中
  • 查看user表的结构
use mysql;
desc user;
  • 主要字段说明:
    • Host表示允许访问的主机
    • User表示用户名
    • password表示密码,为加密后的值

查看所有用户

select host,user,password from user;

结果 taobao.com jd.com itheima.com zhangsan 123456

mysql> select host,user,password from user;
+-----------+------+-------------------------------------------+
| host      | user | password                                  |
+-----------+------+-------------------------------------------+
| localhost | root | *6BB4837EB74329105EE4568DDA7DC67ED2CA2AD9 |
+-----------+------+-------------------------------------------+
1 row in set (0.00 sec)

3. 创建账户、授权

  • 需要使用实例级账户登录后操作,以root为例
  • 常用权限主要包括:create、alter、drop、insert、update、delete、select
  • 如果分配所有权限,可以使用all privileges

步骤

步骤一:创建用户
create user '用户名'@'主机' identified by '密码';

步骤二:授权
grant 权限 on 数据库.表名 to '用户名'@'主机名';

示例1:

创建一个laowang的账号,密码为123456,只能通过本地(localhost)访问, 并且只能对day26数据库中的所有表进行操作

  • step1:使用root登录
mysql -uroot -p
回车后写密码,然后回车
  • step2:创建账户并授予所有权限
create user 'laowang'@'localhost' identified by '123456';  # 创建用户

grant select on day26.user to 'laowang'@'localhost';      # 授予select的权限

说明

  • 可以操作day26数据库的user表,方式为:day26.user

  • 访问主机通常使用 百分号% 表示此账户可以使用任何ip的主机登录访问此数据库

  • 访问主机可以设置成 localhost或具体的ip,表示只允许本机或特定主机访问

  • 查看用户有哪些权限

show grants for 'laowang'@'localhost';

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CizuGkSP-1581258609020)(./img/01.jpg)]

  • step3:退出root的登录
quit
  • step4:使用laowang账户登录
mysql -ulaowang -p654321
  • 登录后效果如下图
    python正则表达式和数据库_第9张图片
  • 查看day26数据库中的表
    python正则表达式和数据库_第10张图片
  • 查看day26.user表中的数据
    python正则表达式和数据库_第11张图片
  • 前面的这些查询操作我们都能愉快的验证通过,那么接下来我们来修改一下数据试试
update user set money=3000;

在这里插入图片描述

这里提示说:更新命令被拒绝啦!laowang这个用户没有对user表执行update的权限.还记得我们前面授予的权限吗?

mysql> grant select on day26.user to 'laowang'@'localhost';
Query OK, 0 rows affected (0.00 sec)

我们仅仅只是授予了laowang能够查询day26库中的user

示例2

创建一个laoli的账号,密码为123456,可以任意电脑进行链接访问, 并且对day26数据库中的所有表拥有所有权限

**注意:**需要使用root账户才能进行创建用户和授权

mysql> create user 'laoli'@'%' identified by '123456';
Query OK, 0 rows affected (0.01 sec)

mysql> grant all privileges on day26.* to 'laoli'@'%';
Query OK, 0 rows affected (0.00 sec)
  • 使用'laoli'@'localhost'进行登录
    python正则表达式和数据库_第12张图片

  • 查看所有的表

python正则表达式和数据库_第13张图片

​ 哇塞,当我们授权day26.*的时候,我们可以查看到day26这个数据库的中的所有的表喔!

  • 下面我们来查看一下表中的数据

python正则表达式和数据库_第14张图片

  • 我们再来更新一下数据试试
    • 看这个时候,就没有再出现权限被拒绝的情况啦! 因为laoli的权限为all privileges

python正则表达式和数据库_第15张图片


账户管理(二)

1. 删除权限

revoke 权限名称 on 数据库.表名 from 账户@主机 

如:
revoke select on day26.user from laoli@'%';
刷新权限列表
flush privileges;

在这里插入图片描述

在这里插入图片描述

2. 修改密码

使用root登录,修改mysql数据库的user表

  • 使用password()函数进行密码加密
set password for '用户名'@'地址'=password('新密码')

例:
set password for 'laowang'@'localhost'=password('123456');
  • 注意修改完成后需要刷新权限
刷新权限:flush privileges
mysql> set password for 'laowang'@'localhost'=password('123456');
Query OK, 0 rows affected (0.00 sec)

mysql> flush privileges;
Query OK, 0 rows affected (0.02 sec)

!!! 忘记mysql默认密码

假设我们忘记了密码或者输错了密码, 输入 mysql -uroot -p ,回车输入密码进入数据库就会出现这样到错误;

Access denied for user 'root'@'localhost' (using password: YES)

解决方案:密码置空+修改密码

第一步,停止MySQL服务

以管理员到身份打开cmd命令行窗口!

C:\WINDOWS\system32>net stop mysql
MySQL 服务正在停止.
MySQL 服务已成功停止。

第二步,编辑MySQL配置文件:

编辑mysql的配置文件

C:\Program Files\MySQL\MySQL Server 5.5\my.ini

在[mysqld]段下加入一行“skip-grant-tables”。让mysql跳过正常验证(非常危险,尽快操作)

[mysqld]
skip-grant-tables
# The TCP/IP Port the MySQL Server will listen on
port=3306

保存文件,并退出编辑模式

第三步,启动MySQL服务:

C:\WINDOWS\system32>net start mysql
MySQL 服务正在启动 .
MySQL 服务已经启动成功。

第四步,控制台直接输入mysql 即可登录到 mysql控制台

python正则表达式和数据库_第16张图片

第五步,修改密码,将laowang的密码设置为123123

use mysql;

update user set password=password('123123') where user='laowang';

第六步,退出控制台,并修改mysql启动方式为普通模式

再次编辑 mysql 配置文件,注释或删除此行 skip-grant-tables 并保存退出

C:\Program Files\MySQL\MySQL Server 5.5\my.ini

第七步:重启 mysql服务,此时密码就为空了

C:\WINDOWS\system32>net stop mysql
MySQL 服务正在停止.
MySQL 服务已成功停止。


C:\WINDOWS\system32>net start mysql
MySQL 服务正在启动 .
MySQL 服务已经启动成功。

第八步: 使用laowang用户,密码为123123登录

C:\WINDOWS\system32>mysql -ulaowang -p123123
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 2
Server version: 5.5.27 MySQL Community Server (GPL)

Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql>

4. 删除账户

  • 语法1:使用root登录
drop user '用户名'@'主机';
例:
drop user 'laowang'@'%';
  • 语法2:使用root登录,删除mysql数据库的user表中数据
delete from user where user='用户名';
例:
delete from user where user='laowang';

-- 操作结束之后需要刷新权限
flush privileges
  • 推荐使用语法1删除用户, 如果使用语法1删除失败,采用语法2方式

忘记 root 账户密码怎么办 !!

  • 一般也轮不到我们来管理 root 账户,所以别瞎卖白粉的心了

数据库编程

1. 概述

从前面我们知道数据库概念包含 数据库文件、服务器和数据库客户端
客户端我们之前已经用过的有cmd命令行,sqlyog等程序。

问题: 如何使用客户端将100000行数据插入到数据库?

大家会发现如果用之前客户端几乎是不可能完全这个任务的, 因为我们不可能去构造出那个插入10w行数据的SQL。可是,如果我们有一个功能能够插入一行数据,借助程序强大的特点-重复,就可以轻而易举的就将10w行数据收入麾下。这种通过使用程序代码的方式去连接数据库服务器,通过和服务器进行交互完成对数据库的增删改查的方式,就称为数据库编程

而此刻学习的pymysql就是一种客户端。

2. Python 中操作 MySQL 步骤

python正则表达式和数据库_第17张图片

如何理解连接 connection 和 游标 cursor

connection就像是连接出发地和目的地的 高速公路 
cursor就像是在高速公路上的货车-拉货
我们使用游标就可以完成对数据的操作
当我们完成操作完成后就可以停下货车,然后公路再停止使用。

3. pymysql的使用

引入模块

from pymysql import connect

3.1 Connection 对象

  • 用于建立与数据库的连接
    调用pymysql模块中的connect()方法
conn=connect(参数列表)

* 参数host:连接的mysql主机,如果本机是'localhost'
* 参数port:连接的mysql主机的端口,默认是3306
* 参数database:数据库的名称
* 参数user:连接的用户名
* 参数password:连接的密码
* 参数charset:通信采用的编码方式,推荐使用utf8
  • 关闭连接
    conn.close()
  • 提交数据
    conn.commit()
  • 撤销数据
    conn.rollback()
  • 通过连接获取游标
    cur = conn.cursor()返回Cursor对象,用于执行sql语句并获得结果

3.2 Cursor游标对象

  • 获取Cursor对象

    # 调用Connection对象的cursor()方法    
    cur =conn.cursor()
    

目的: 执行sql语句(使用频度最高的语句为select、insert、update、delete)

  • 使用游标执行SQL语句

execute(operation [, parameters ])
执行SQL语句,返回受影响的行数,主要用于执行insert、update、delete语句,也可以执行create、alter、drop等语句

  • 关闭游标
    cur.close()

  • 获取结果集中的一条

    cur.fetchone()返回一个元组 形如 (1,‘妲己’,18)

  • 获取结果集中的所有

    cur.fetchall()执行查询时,获取结果集的所有行,一行构成一个元组,再将这些元组装入一个元组返回 形如((1,‘公孙离’,20),(2,‘妲己’,18))

3.3 pymysql完成数据查询

import pymysql

# 创建和数据库服务器的连接 服务器地址   端口    用户名     密码  数据库名 通信使用字符和数据库字符集一致
conn = pymysql.connect(host='localhost', port=3306, user='root', password='mysql',database='python_test_1', charset='utf8')

# 获取游标
cursor = conn.cursor()

# 执行SQL语句 返回值就是SQL语句在执行过程中影响的行数
sql = """select * from hero;"""

row_count = cursor.execute(sql)
print("SQL语句执行影响的行数%d" % row_count)

# 取出结果集中一行  返回的结果是一行 (1, '妲己', 2)
# print(cursor.fetchone())

# 取出结果集中的所有数据  返回 ((一行数据),(),())
# ((1, '妲己', 2), (2, '李白', 1), (3, '程咬金', 3), (4, '亚瑟', 5), (5, '荆轲', 99))
for line in cursor.fetchall():
    print(line)

# 关闭游标
cursor.close()

# 关闭连接
conn.close()

4. pymysql增删改

import pymysql

conn = pymysql.connect(host='127.0.0.1',port=3306,user='root',password='mysql',db='python_test_1', charset='utf8')

# 通过连接获取游标
cursor = conn.cursor()


# sql = "delete from hero where id = 5;"
# sql = insert into hero (name) values ('西部大坏蛋孙悟空');
sql = "update hero set kongfuid=444 where id = 4;"

row_count = cursor.execute(sql)
print("SQL语句执行影响的行数%d" % row_count)

# 提交数据到数据库
# conn.commit()

# 回滚数据到什么都不做的状态 即撤销刚刚的修改
conn.rollback()

# 关闭游标和连接
cursor.close()
conn.close()

关于提交commit

commit将修改提交到数据库,保存修改


注意pymysql中数据需要手动提交commit才能保存到数据库中


5. SQL注入

参数化列表防止SQL注入

什么是SQL注入

产生原因: 后台将用户提交的带有恶意的数据和SQL进行字符串方式的拼接,从而影响了SQL语句的语义,最终产生数据泄露的现象。
如果防止: sql语句的参数化, 将SQL语句的所有数据参数存在一个列表中传递给execute函数的第二个参数
count = cs1.execute('select * from goods where name=%s', params)


注意

* 此处不同于python的字符串格式化,必须全部使用%s占位
* 所有参数所需占位符外不需要加引号


from pymysql import connect

def main():

    find_name = input("请输入物品名称:")

    # 创建Connection连接
    conn = connect(host='localhost',port=3306,user='root',password='mysql',database='jing_dong',charset='utf8')
    # 获得Cursor对象
    cs1 = conn.cursor()


    # # 非安全的方式
    # # 输入 " or 1=1 or "   (双引号也要输入)
    # sql = 'select * from goods where name="%s"' % find_name
    # print("""sql===>%s<====""" % sql)
    # # 执行select语句,并返回受影响的行数:查询所有数据
    # count = cs1.execute(sql)

    # 安全的方式
    # 构造参数列表 
    params = [find_name]
    # 执行select语句,并返回受影响的行数:查询所有数据
    count = cs1.execute('select * from goods where name=%s', params)
    # 注意:
    # 如果要是有多个参数,需要进行参数化
    # 那么params = [数值1, 数值2....],此时sql语句中有多个%s即可 
    
    # 打印受影响的行数
    print(count)
    # 获取查询的结果
    # result = cs1.fetchone()
    result = cs1.fetchall()
    # 打印查询的结果
    print(result)
    # 关闭Cursor对象
    cs1.close()
    # 关闭Connection对象
    conn.close()

if __name__ == '__main__':
    main()

学生信息管理系统

本案例由3个页面组成:

  1. 登录页面
  2. 注册页面
  3. 数据操作页面

用户若想使用我们这个系统,必须先注册,注册成功之后自动打开登录页面,登录成功即进入数据操作页面

案例展示

数据库创建

当前我们是要来开发一个新的项目,为了不和其它数据库糅杂在一下,我们就来新建一个数据库吧!

create database itheima;

创建完数据库还不行啊,我们最好还能让管理员给我们一个账号,该账号只能在itheima这个数据库中使用,所以我们需要使用root账号登陆

例如,我们创建一个系统管理员账号:admin 密码:123456

create user admin@'localhost' identified by '123456'

创建完用户,我们还不要忘记对该用户授予itheima这个数据库下所有的权限喔!

grant all privileges on itheima.* to admin@'localhost';

至此,我们为这个新项目所做的数据库准备工作就完成啦!

表的创建

我们去创建一张专门用于存放系统使用人员的表,让它和我们系统要记录的学生信息表分开

例如,我们创建一张users的表专门用于存放管理员门的表

create table if not exists user(
	id int primary key auto_increment,
    username varchar(20),
    password varchar(50),
	nickname varchar(20)
);

创建一张专门用于保存学生信息的表student

create table if not exists student(
                    sid int primary key auto_increment,
                    name varchar(20),
                    age int,
                    gender varchar(2)    
              )

搭建主窗体

主窗体拥有一个菜单栏,它里面有个操作选项,我们可以进行菜单切换,所以这里我们需要操作菜单栏

# 添加操作菜单
menu_bar = self.window.menuBar()
operate_menu =menu_bar.addMenu("操作")

# 向菜单中添加两个动作
loginAction = QAction("登录")
loginAction.triggered.connect(self.show_login)
operate_menu.addAction(loginAction)

registerAction = QAction("注册")
registerAction.triggered.connect(self.show_register)
operate_menu.addAction(registerAction)

要想实现窗体的切换,我们还需要使用QT中的自定义信号

from PyQt5.QtCore import pyqtSignal


class LoginWidget(QWidget):
    # 声明一个信号
    login_success = pyqtSignal()
    
    ....
    
    # 向外发送一个信号
    self.login_success.emit()

完整的主窗体实现代码如下

from pymysql import connect
from PyQt5.QtWidgets import QApplication,QMainWindow,QAction
from RegisterWidget import RegisterWidget
from LoginWidget import LoginWidget
from IndexWidget import IndexWidget
import sys

class StuSystem:

    def __init__(self):
        # 初始化数据库
        # self.create_db()

        # 创建一个应用程序
        app = QApplication(sys.argv)

        # 创建一个主窗体
        self.mainWindow = QMainWindow()
        # 设置窗口的固定大小
        self.mainWindow.setFixedSize(800,400)

        # 给窗口增加一个菜单栏
        menuBar = self.mainWindow.menuBar()
        operation = menuBar.addMenu("操作")

        # 给菜单添加动作
        loginAction = QAction("登录")
        # 将loginAction添加到操作这个菜单里
        operation.addAction(loginAction)
        # 设置loginAction的信号和槽
        loginAction.triggered.connect(self.show_login)

        # 给菜单添加注册的动作
        registerAction = QAction("注册")
        # 将registerAction添加到这个菜单中
        operation.addAction(registerAction)
        # 设置RegisterAction的信号和槽
        registerAction.triggered.connect(self.show_register)

        # 默认打开注册页面
        self.show_index()

        # 将主窗口显示出来
        self.mainWindow.show()
        # 让程序一直处于运行的状态
        sys.exit(app.exec())

    def show_index(self):
        print("显示主要功能页")
        indexWidget = IndexWidget()
        self.mainWindow.setCentralWidget(indexWidget)

    def show_login(self):
        print("显示登录页面")
        loginWidget = LoginWidget()
        loginWidget.login_success.connect(self.show_index)
        self.mainWindow.setCentralWidget(loginWidget)

    def show_register(self):
        print("显示注册页面")
        registerWidget = RegisterWidget()
        # 绑定信号和槽
        registerWidget.register_success.connect(self.show_login)
        self.mainWindow.setCentralWidget(registerWidget)



    def create_db(self):
        # 建立连接
        conn = connect(host="localhost",port=3306,user="admin",password="123456")

        # 获取执行SQL的游标
        cursor = conn.cursor()

        # 创建数据库
        sql = "create database if not exists itheima"
        # 执行sql
        cursor.execute(sql)
        # 选中数据库
        cursor.execute("use itheima")
        # 创建管理员账号表
        sql = """create table if not exists user(
	id int primary key auto_increment,
    username varchar(20),
    password varchar(50),
	nickname varchar(20)
);"""
        # 创建表
        cursor.execute(sql)

        # 创建用于保存学生数据的表
        sql = """create table if not exists student(
                    sid int primary key auto_increment,
                    name varchar(20),
                    age int,
                    gender varchar(2)    
              )"""
        cursor.execute(sql)

        # 释放资源
        cursor.close()
        # 断开连接
        conn.close()


if __name__ == '__main__':
    StuSystem()

编写注册页面

代码实现

from PyQt5.QtWidgets import *
from PyQt5.Qt import QFont
from PyQt5.QtCore import pyqtSignal

class RegisterWidget(QWidget):
    # 定义一个注册成功的信号
    register_success = pyqtSignal()

    def __init__(self):
        super(RegisterWidget, self).__init__()

        # 整个注册页面是水平布局
        hbox = QHBoxLayout(self)

        hbox.addStretch()

        # 添加要显示的内容
        vbox = QVBoxLayout()
        label = QLabel("学生管理系统")
        font = QFont("微软雅黑",30)
        font.setBold(True)
        label.setFont(font)
        vbox.addWidget(label)
        hbox.addLayout(vbox)

        # 添加注册信息框
        formLayout = QFormLayout()

        self.usernameEdit = QLineEdit()
        formLayout.addRow("用户名:",self.usernameEdit)

        self.passwordEdit = QLineEdit()
        self.passwordEdit.setEchoMode(QLineEdit.Password)
        formLayout.addRow("密码:", self.passwordEdit)

        self.nicknameEdit = QLineEdit()
        formLayout.addRow("昵称:", self.nicknameEdit)

        pushButton = QPushButton("注册")
        pushButton.clicked.connect(self.register)
        formLayout.addRow("",pushButton)


        vbox.addLayout(formLayout)

        hbox.addStretch()

    def register(self):
        # print("假装注册逻辑已经完成啦!")
        # 获取用户输入的内容
        username = self.usernameEdit.text()
        password = self.passwordEdit.text()
        nickname = self.nicknameEdit.text()

        from pymysql import connect
        conn = connect(host="localhost",port=3306,user="admin",password="123456",database="itheima")

        sql = "insert into user values(null,%s,%s,%s)"

        cursor = conn.cursor()
        ret = cursor.execute(sql,[username,password,nickname])
        # 需要提交事务
        conn.commit()

        if ret==1:
            print("注册成功!")
            QMessageBox.information(None, '提示', '恭喜您,注册成功!')
            # 发送信号
            self.register_success.emit();

        # 释放资源
        cursor.close()
        # 断开连接
        conn.close()

编写登录页面

代码实现

from PyQt5.QtWidgets import *
from PyQt5.Qt import QFont
from PyQt5.QtCore import pyqtSignal

class LoginWidget(QWidget):
    # 定义一个注册成功的信号
    login_success = pyqtSignal()

    def __init__(self):
        super(LoginWidget, self).__init__()

        # 整个注册页面是水平布局
        hbox = QHBoxLayout(self)

        hbox.addStretch()

        # 添加要显示的内容
        vbox = QVBoxLayout()
        label = QLabel("学生管理系统")
        font = QFont("微软雅黑",30)
        font.setBold(True)
        label.setFont(font)
        vbox.addWidget(label)
        hbox.addLayout(vbox)

        # 添加注册信息框
        formLayout = QFormLayout()

        self.usernameEdit = QLineEdit()
        formLayout.addRow("用户名:",self.usernameEdit)

        self.passwordEdit = QLineEdit()
        self.passwordEdit.setEchoMode(QLineEdit.Password)
        formLayout.addRow("密码:", self.passwordEdit)

        pushButton = QPushButton("登录")
        pushButton.clicked.connect(self.login)
        formLayout.addRow("",pushButton)


        vbox.addLayout(formLayout)

        hbox.addStretch()

    def login(self):
        # 获取用户输入的内容
        username = self.usernameEdit.text()
        password = self.passwordEdit.text()

        from pymysql import connect
        conn = connect(host="localhost", port=3306, user="admin", password="123456", database="itheima")

        sql = "select * from user where username=%s and password=%s"

        cursor = conn.cursor()
        cursor.execute(sql, [username, password])

        user = cursor.fetchone();

        if user:
            print("登录成功!")
            # 发送信号
            self.login_success.emit();
        else:
            QMessageBox.information(None,"提示","用户名或密码错误!")

        # 释放资源
        cursor.close()
        # 断开连接
        conn.close()

补充:在这个案例中,我们的所有密码都是明文存储的,为了安全起见,我们其实可以将我们的密码加密之后再保存到数据库中

这里我们可以使用md5这种加密方式,例如

str = "123456"
m = hashlib.md5(str.encode("utf-8")).hexdigest()

如果你觉得采用这种方式还是不安全的话,我们还可以对我们的md5加密算法进行加盐操作,让用户输入的值拼接上一个特殊的字符串

str = "123456"+"&%%*(%)"
m = hashlib.md5(str.encode("utf-8")).hexdigest()

编写项目主页

在这一小节中,我们将给大家介绍qt中是如何去操作数据库的!

首先我们要给大家介绍的是QT中如何进行数据库的连接

 	# 创建一个QT数据库客户端,这里的参数不能瞎填, https://doc.qt.io/qt-5/qsqldatabase.html#addDatabase
    db =  QSqlDatabase.addDatabase("QMYSQL")
    # 设置host
    db.setHostName("localhost")
    # 设置端口号
    db.setPort(3306)
    # 设置连接用户名
    db.setUserName("admin")
    # 设置连接的密码
    db.setPassword("123456")
    # 设置连接的数据库名称
    db.setDatabaseName("itheima")

    # 打开数据库
    db.open()

如果想使用QT直接执行SQL命令的话,我们需要用到QSQLQuery

# 传入上面创建好的数据库客户端即可
query = QSqlQuery(db)

# 执行建表语句
query.exec("""
                  create table if not exists student(
                        sid int primary key,
                        name varchar(20),
                        age int,
                        sex varchar(2)
                    );
               """)


def test_query(db):
    query = QSqlQuery(db)
    ret = query.exec("select * from student")
    print(ret)
    while query.next():
        print(query.value(0))
        print(query.value(1))
        print(query.value(2))
        print(query.value(3))
        print("====================")


def test_insert(db):
    query = QSqlQuery(db);
    ret = query.exec("insert into student values(%d,'%s',%d,'%s')"%(2001,"老王",36,"男"))
    print(query.lastError().text())
    print(ret)

def test_update(db):
    query = QSqlQuery(db);
    ret = query.exec("update student set name='%s' where name='%s'"%("小王","老王"))
    print(query.lastError().text())
    print(ret)

def test_delete(db):
    query = QSqlQuery(db);
    ret = query.exec("delete from student where sid=%d"%2001)
    print(query.lastError().text())
    print(ret)

注意:

qt库中默认缺少mysql的驱动,

若python是32位的,则需要提供32位的libmysql.dll文件

若python是64位的,则需要提供64位的libmysql.dll文件

并将它复制到python安装目录\Lib\site-packages\PyQt5\Qt\bin

代码实现

from PyQt5.QtWidgets import *
from PyQt5.QtSql import QSqlTableModel,QSqlDatabase
from PyQt5.QtCore import Qt


class IndexWidget(QWidget):

    def __init__(self):
        super(IndexWidget, self).__init__()

        hbox = QHBoxLayout(self)

        # 左侧按钮组
        groupBox = QGroupBox("数据库操作")
        hbox.addWidget(groupBox)
        # 设置groupBox布局方式
        vbox = QVBoxLayout()
        groupBox.setLayout(vbox)

        # 查看
        query_btn = QPushButton("查看数据")
        query_btn.clicked.connect(self.query_db)
        vbox.addWidget(query_btn)
        # 增加
        add_btn = QPushButton("增加一行")
        add_btn.clicked.connect(self.add)
        vbox.addWidget(add_btn)
        # 删除
        delete_btn = QPushButton("删除一行")
        delete_btn.clicked.connect(self.delete)
        vbox.addWidget(delete_btn)
        # 退出
        exit_btn = QPushButton("退出")
        exit_btn.clicked.connect(QApplication.exit)
        vbox.addWidget(exit_btn)

        # 右侧表格显示区域
        self.tableView = QTableView()
        hbox.addWidget(self.tableView)

        # 创建一个QT数据库客户端
        db =  QSqlDatabase.addDatabase("QMYSQL")
        # 设置host
        db.setHostName("localhost")
        # 设置端口号
        db.setPort(3306)
        # 设置连接用户名
        db.setUserName("admin")
        # 设置连接的密码
        db.setPassword("123456")
        # 设置连接的数据库名称
        db.setDatabaseName("itheima")

        # 打开数据库
        db.open()

        self.tableModel = QSqlTableModel(db=db)
        self.tableModel.setTable("student")
        self.tableModel.setEditStrategy(QSqlTableModel.OnFieldChange)

        self.tableModel.setHeaderData(0,Qt.Horizontal,"学号")
        self.tableModel.setHeaderData(1,Qt.Horizontal,"姓名")
        self.tableModel.setHeaderData(2,Qt.Horizontal,"年龄")
        self.tableModel.setHeaderData(3,Qt.Horizontal,"性别")

        # 将封装好的模型交给tableWidget
        self.tableView.setModel(self.tableModel)

    def query_db(self):
        print(self.tableModel.lastError().text())
        self.tableModel.select()

    def add(self):
        self.tableModel.insertRow(self.tableModel.rowCount())

    def delete(self):
        # 找到当前选中行的下标
        index = self.tableView.currentIndex().row()
        self.tableModel.removeRow(index)
        self.tableModel.select()

你可能感兴趣的:(Python)