数据库(Database)是按照数据结构来组织、存储和管理数据的仓库。它产生于距今六十多年前,随着信息技术和市场的发展,特别是二十世纪九十年代之后,数据管理再也不仅仅是存储和管理数据,而转变成用户所须要的各类数据管理方式。数据库有不少种类型,从简单的存储有各类数据的表格到可以进行海量数据存储的大型数据库系统。python
关系型数据库系统(Relational Database Management System,RDBMS)是创建在关系模型基础上的数据库,借助于集合代数等数学概念和方法来处理数据库中的数据。现实世界中的各类实体以及实体之间的各类联系均用关系模型来表示。mysql
关系型数据库有如下特色:sql
RDBMS术语:数据库
MySQL是当前最流行的关系型数据库,在Web应用方面MySQL是最好的关系型数据库。MySQL由瑞典MySQL AB公司开发,目前属于Oracle公司。编程
猛戳这里访问MySQL官网ubuntu
安装MySQL服务器
Windows可在官网下载安装包安装,Linux上可经过yum或apt等安装包管理工具安装。session
在ubuntu 16.04下安装MySQL,经过命令sudo apt-get install mysql-server。经过该命令安装MySQL时会在安装过程当中提示设置root用户的密码。数据结构
本文中使用MySQL的环境均为ubuntu server 16.04.3。app
验证MySQL安装
在成功安装MySQL后,一些基础表会初始化,在服务器启动后,能够经过mysqladmin工具来获取服务器状态。
fangyu@python:~$ mysqladmin --version mysqladmin Ver 8.42 Distrib 5.7.20, for Linux on x86_64
若是以上命令执行后未输出任何信息,则说明MySQL安装不成功。
启动及关闭MySQL
#经过如下命令检查MySQL服务器是否启动 ps -ef|grep mysqld
若是MySQL已经启动,以上命令将输出MySQL进程列表。
#经过如下命令启动MySQL服务器 /etc/init.d/mysql start
#经过如下命令能够关闭正在运行的MySQL服务器 mysqladmin -u root -p shutdown
登陆MySQL
#经过如下命令能够登陆MySQL服务器 mysql -u root -p Enter password: #输入密码便可
在ubuntu 16.04上经过apt安装MySQL时,在安装过程当中会提示设置root用户的密码,因此这里须要使用密码登陆。
登陆成功后会出现MySQL提示符,以下
mysql>
说明以成功链接上MySQL服务器,能够在该命令提示符下执行SQL命令。MySQL的SQL语句以;做为结束标识。
MySQL用户设置
使用root登陆以后能够设置新用户并为新用户配置权限。
建立新用户
create user '用户名'@'host' identified by '密码'; #命令详解: #host - 指定该用户在哪一个主机上能够登陆,若是是本地用户可使用localhost;若是想让该用户能够从任意主机登陆,可使用通配符%;从指定主机登陆可直接使用IP地址
为新用户配置权限
grant 权限 on 数据库.表名 to '用户名'@'host'; #命令详解: #权限 - 用户的操做权限,如select、insert、update等,若是要受权全部权限,可使用all #数据库.表名 - 受权用户操做指定的数据库和表,若是要受权用户对全部数据库及表的操做,可使用*.* #注意:使用上面的命令所受权的用户没法给其余用户受权,想让该用户能够受权,能够经过如下命令 grant 权限 on 数据库.表名 to '用户名'@'host' with grant option;
#经过如下命令查看用户的受权信息 show grants for '用户名'@'host';
更改用户密码
set password for '用户名'@'host'=password('密码'); #为当前用户更改密码 set password=password('密码'); #password() - 使用MySQL提供的password函数对密码进行加密
撤销用户权限
revoke 权限 on 数据库.表名 from '用户名'@'host'; #注意:撤销权限时必须于添加权限的内容一致
删除用户
drop user '用户名'@'host';
MySQL中的操做权限
MySQL管理命令
show databases:列出MySQL的数据库列表
use 数据库:选择要操做的数据库,使用该命令后全部的MySQL命令都只针对该数据库
show tables:显示指定数据库的全部表,使用该命令前须要使用use命令来选择要操做的数据库
show columns from 表名:显示数据表的属性,属性类型,主键信息,是否为NULL,默认值等其余信息,也可以使用desc 表名
show index from 表名:显示数据表的详细索引信息,包括PRIMARY KEY(主键)
create database 数据库名 charset 'utf8':建立一个数据库,并使其支持中文
drop database 数据库名:删除数据库
MySQL中定义数据字段的类型对于数据库的优化是很是重要的。
MySQL支持多种数据类型,大体能够分为三类:数值、日期/时间和字符串(字符)类型。
数值类型
MySQL支持全部标准SQL数值数据类型。
这些类型包括严格数值数据类型(INTEGER、SMALLINT、DECIMAL和NUMERIC),以及近似数值数据类型(FLOAT、REAL和DOUBLE PRECISION)。
关键字INT是INTEGER的同义词,关键字DEC是DECIMAL的同义词。
BIT数据类型保存位字段值,而且支持MyISAM、MEMORY、InnoDB和BDB表。
做为SQL标准的扩展,MySQL也支持整数类型TINYINT、MEDIUMINT和BIGINT。下面的表显示了须要的每一个整数类型的存储和范围。
时间和日期类型
表示时间值的日期和时间类型为DATETIME、DATE、TIMESTAMP、TIME和YEAR。
每一个时间类型有一个有效值范围和一个"零"值,当指定不合法的MySQL不能表示的值时使用"零"值。
TIMESTAMP类型有专有的自动更新特性。
字符串类型
字符串类型指CHAR、VARCHAR、BINARY、VARBINARY、BLOB、TEXT、ENUM和SET。
CHAR和VARCHAR类型相似,但它们保存和检索的方式不一样。它们的最大长度和是否尾部空格被保留等方面也不一样。在存储或检索过程当中不进行大小写转换。
BINARY和VARBINARY类相似于CHAR和VARCHAR,不一样的是它们包含二进制字符串而不是非二进制字符串。也就是说,它们包含字节字符串而不是字符字符串。这说明它们没有字符集,而且排序和比较基于列值字节的数值值。
BLOB是一个二进制大对象,能够容纳可变数量的数据。有4种BLOB类型:TINYBLOB、BLOB、MEDIUMBLOB和LONGBLOB。它们只是可容纳值的最大长度不一样。
有4种TEXT类型:TINYTEXT、TEXT、MEDIUMTEXT和LONGTEXT。这些对应4种BLOB类型,有相同的最大长度和存储需求。
建立数据表
create table 表名(字段名,字段数据类型);
实例:在testdb中建立一个student表,有id,name,register_date三个字段,其中id为主键
mysql> create table student( -> id int not null auto_increment, -> name char(32) not null, -> register_date date not null, -> primary key(id) -> ); #命令详解: #not null - 字段不为null,设置该属性后在输入该字段的数据为null时将会报错 #auto_increment - 自增,通常用于主键,数值会自动加1 #primary key - 定义主键,可使用多个字段来定义主键,字段间以逗号分隔
插入数据
insert into 表名(字段1,字段2,...,字段n) values (值1,值2,...,值n);
查询数据
select 字段 from 表名 [where 条件] [offset m] [limit n]; #命令详解: #查询语句中可使用一个或多个表,表之间使用逗号分隔,并使用where语句来设定查询条件 #select命令能够读取一条或多条记录 #可使用*来代替其余字段,select语句会返回表的全部字段数据 #可使用where语句来包含任何条件 #能够经过offset指定select语句开始查询的数据偏移量,默认状况下偏移量为0,需配合limit使用 #可使用limit属性来设定返回的记录树
where子句
如下操做符能够用于where子句中
假定A为10,B为20
like子句
select 字段 from 表名 where 条件 like 匹配条件; #实例 select * from student where name like 'g%'; select * from student where name like binary 'G%'; #只匹配大写
排序
select 字段 from 表名 order by 字段 [asc or desc]; #命令详解: #使用asc或desc关键字来设置查询结果按升序或者降序排序,默认状况下按升序排序
group by分组
select 字段,函数(自定义名称) from 表名 [where 条件] group by 字段; #实例 mysql> select * from student; +----+--------+---------------+ | id | name | register_date | +----+--------+---------------+ | 1 | gougou | 2017-12-22 | | 2 | maomao | 2017-12-25 | | 3 | guigui | 2017-12-25 | | 4 | niuniu | 2017-12-29 | | 5 | tutu | 2017-12-30 | +----+--------+---------------+ 5 rows in set (0.00 sec) #统计每一个名字出现的次数并分组 mysql> select name,count('计数') from student group by name; +--------+-----------------+ | name | count('计数') | +--------+-----------------+ | gougou | 1 | | guigui | 1 | | maomao | 1 | | niuniu | 1 | | tutu | 1 | +--------+-----------------+ #使用with rollup mysql> select name,count('c') as '计数' from student group by name with rollup; +--------+--------+ | name | 计数 | +--------+--------+ | gougou | 1 | | guigui | 1 | | maomao | 1 | | niuniu | 1 | | tutu | 1 | | NULL | 5 | +--------+--------+ #可使用 coalesce 来设置一个能够取代 NUll 的名称 mysql> select coalesce(name,'总计数'),count('计数') from student group by name with rollup; +----------------------------+-----------------+ | coalesce(name,'总计数') | count('计数') | +----------------------------+-----------------+ | gougou | 1 | | guigui | 1 | | maomao | 1 | | niuniu | 1 | | tutu | 1 | | 总计数 | 5 | +----------------------------+-----------------+
修改数据
update 表名 set 字段1=值1,字段2=值2 [where 条件];
删除数据
delete from 表名 [where 条件];
修改表名及字段
#添加字段 alter table 表名 add 字段; #实例:alter table student add phone int not null; #删除字段 alter table 表名 drop 字段; #实例:alter table student drop phone; #修改字段类型及名称 #使用modify子句 alter table 表名 modify 字段 修改后的数据类型; #实例: alter table student modify name char(48) not null; #使用change子句 alter table 表名 change 字段名 修改后的字段名 修改后的数据类型; #实例1:alter table student change name name char(32) not null; #不修改字段名 #实例2:alter table student change name stu_name char(48) not null; #修改字段名 #修改字段时添加是否null值及是否设置默认值 alter table 表名 modify 字段 数据类型 not null default 默认值; #修改表名 alter table 表名 rename to 修改后的表名;
外键关联
外键是一个特殊的索引,用于关联两个表,用于维护数据的完整性。
#实例 mysql> create table student( -> id int not null auto_increment, -> name char(32) not null, -> class_id int not null, -> primary key(id), -> foreign key(class_id) references class(id) #设置外键 -> );
外键约束
mysql> insert into student (name,class_id) values('wangwang',3); ERROR 1452 (23000): Cannot add or update a child row: a foreign key constraint fails (`testdb`.`student`, CONSTRAINT `student_ibfk_1` FOREIGN KEY (`class_id`) REFERENCES `class` (`id`)) #插入数据时,当插入的class_id为class表中不存在的id时,报错
mysql> delete from class where id=1; ERROR 1451 (23000): Cannot delete or update a parent row: a foreign key constraint fails (`testdb`.`student`, CONSTRAINT `student_ibfk_1` FOREIGN KEY (`class_id`) REFERENCES `class` (`id`)) #一个表的字段被其余表关联后,没法删除
MySQL null值处理
使用selecet 命令及where子句进行查询时,当提供的查询条件字段为null时,该命令可能没法正常工做。为处理这种状况,MySQL提供了三大运算符:
is null:当列的值是null时,此运算符返回true
is not null:当列的值不为null时,此运算符返回true
<=>:比较操做符(不一样于=运算符),当比较的两个值为null时返回true
关于 NULL 的条件比较运算是比较特殊的。你不能使用 = NULL 或 != NULL 在列中查找 NULL 值 。
在MySQL中,NULL值与任何其它值的比较(即便是NULL)永远返回false,即 NULL = NULL 返回false 。
MySQL中处理NULL使用IS NULL和IS NOT NULL运算符。
链接查询
MySQL的join能够在两个或多个表中查询数据。在select、update和delete语句中使用join来联合多表查询。
join按照功能大体分为如下三类:
inner join(内链接,或等值链接):获取两个表中字段匹配关系的记录。
left join(左链接):获取左表全部记录,即便右表没有对应的匹配记录。
right join(右链接):与left join相反,用于获取右表全部记录,即便左表没有对应匹配的记录。
实例:
有如下两张表
#class表 +----+----------+ | id | class | +----+----------+ | 1 | animal-1 | | 2 | animal-2 | | 3 | animal-3 | +----+----------+ #student表 +----+--------+----------+ | id | name | class_id | +----+--------+----------+ | 2 | gougou | 1 | | 3 | maomao | 2 | | 4 | tutu | 1 | +----+--------+----------+
inner join(内链接)
mysql> select * from class inner join student on class.id=student.class_id; +----+----------+----+--------+----------+ | id | class | id | name | class_id | +----+----------+----+--------+----------+ | 1 | animal-1 | 2 | gougou | 1 | | 2 | animal-2 | 3 | maomao | 2 | | 1 | animal-1 | 4 | tutu | 1 | +----+----------+----+--------+----------+ #另外一种写法 mysql> select class.*,student.* from class,student where class.id=student.class_id; +----+----------+----+--------+----------+ | id | class | id | name | class_id | +----+----------+----+--------+----------+ | 1 | animal-1 | 2 | gougou | 1 | | 2 | animal-2 | 3 | maomao | 2 | | 1 | animal-1 | 4 | tutu | 1 | +----+----------+----+--------+----------+ #配合where子句 mysql> select * from class inner join student on class.id=student.class_id where class_id=1; +----+----------+----+--------+----------+ | id | class | id | name | class_id | +----+----------+----+--------+----------+ | 1 | animal-1 | 2 | gougou | 1 | | 1 | animal-1 | 4 | tutu | 1 | +----+----------+----+--------+----------+ mysql> select class.*,student.* from class,student where class.id=student.class_id and class_id=1; +----+----------+----+--------+----------+ | id | class | id | name | class_id | +----+----------+----+--------+----------+ | 1 | animal-1 | 2 | gougou | 1 | | 1 | animal-1 | 4 | tutu | 1 | +----+----------+----+--------+----------+
left join(左链接)
mysql> select * from class left join student on class.id=student.class_id; +----+----------+------+--------+----------+ | id | class | id | name | class_id | +----+----------+------+--------+----------+ | 1 | animal-1 | 2 | gougou | 1 | | 2 | animal-2 | 3 | maomao | 2 | | 1 | animal-1 | 4 | tutu | 1 | | 3 | animal-3 | NULL | NULL | NULL | +----+----------+------+--------+----------+
right join(右链接)
mysql> select * from class right join student on class.id=student.class_id; +------+----------+----+--------+----------+ | id | class | id | name | class_id | +------+----------+----+--------+----------+ | 1 | animal-1 | 2 | gougou | 1 | | 1 | animal-1 | 4 | tutu | 1 | | 2 | animal-2 | 3 | maomao | 2 | +------+----------+----+--------+----------+
full join,MySQL不支持full join,可使用另外一种方法实现
mysql> select * from class left join student on class.id=student.class_id union -> select * from class right join student on class.id=student.class_id; +------+----------+------+--------+----------+ | id | class | id | name | class_id | +------+----------+------+--------+----------+ | 1 | animal-1 | 2 | gougou | 1 | | 2 | animal-2 | 3 | maomao | 2 | | 1 | animal-1 | 4 | tutu | 1 | | 3 | animal-3 | NULL | NULL | NULL | +------+----------+------+--------+----------+
事务
MySQL 事务主要用于处理操做量大,复杂度高的数据。好比说,在人员管理系统中,你删除一我的员,你即须要删除人员的基本资料,也要删除和该人员相关的信息,如信箱,文章等等,这样,这些数据库操做语句就构成一个事务!
通常来讲,事务是必须知足4个条件(ACID): Atomicity(原子性)、Consistency(稳定性)、Isolation(隔离性)、Durability(可靠性)
使用begin开始一个事务;使用rollback进行回滚,这样数据将不会写入数据库;使用commit进行提交,写入数据库
索引
MySQL索引的创建对于MySQL的高效运行是很重要的,索引能够大大提升MySQL的检索速度。
索引分单列索引和组合索引。单列索引,即一个索引只包含单个列,一个表能够有多个单列索引,但这不是组合索引。组合索引,即一个索引包含多个列。
建立索引时,你须要确保该索引是应用在 SQL 查询语句的条件(通常做为 WHERE 子句的条件)。
实际上,索引也是一张表,该表保存了主键与索引字段,并指向实体表的记录。
索引的缺点:虽然索引大大提升了查询速度,同时却会下降更新表的速度,如对表进行INSERT、UPDATE和DELETE。由于更新表时,MySQL不只要保存数据,还要保存一下索引文件。创建索引会占用磁盘空间的索引文件。
建立普通索引
普通索引是最基本的索引,没有任何限制。有如下几种方法建立:
CREATE INDEX indexName ON mytable(username(length)); #若是是CHAR,VARCHAR类型,length能够小于字段实际长度;若是是BLOB和TEXT类型,必须指定 length。 ALTER mytable ADD INDEX [indexName] ON (username(length)); #建立表时直接建立 CREATE TABLE mytable( ID INT NOT NULL, username VARCHAR(16) NOT NULL, INDEX [indexName] (username(length)) );
#删除索引 DROP INDEX [indexName] ON mytable;
建立惟一索引
与普通索引不一样,索引列的值必须惟一,但容许有空值。若是是组合索引,则列值的组合必须惟一。有如下几种方法建立:
CREATE UNIQUE INDEX indexName ON mytable(username(length)); ALTER mytable ADD UNIQUE [indexName] ON (username(length)); #建立表的时候直接指定 CREATE TABLE mytable( ID INT NOT NULL, username VARCHAR(16) NOT NULL, UNIQUE [indexName] (username(length)) );
使用alter命令添加和删除索引
ALTER TABLE tbl_name ADD PRIMARY KEY (column_list): 该语句添加一个主键,这意味着索引值必须是惟一的,且不能为NULL。
ALTER TABLE tbl_name ADD UNIQUE index_name (column_list): 这条语句建立索引的值必须是惟一的(除了NULL外,NULL可能会出现屡次)。
ALTER TABLE tbl_name ADD INDEX index_name (column_list): 添加普通索引,索引值可出现屡次。
ALTER TABLE tbl_name ADD FULLTEXT index_name (column_list):该语句指定了索引为 FULLTEXT ,用于全文索引。
ALTER TABLE tbl_name DROP INDEX (index_name); 删除索引
使用alter命令添加和删除主键
主键只能做用于一个列上,添加主键索引时,你须要确保该主键默认不为空(NOT NULL)。实例以下: mysql> ALTER TABLE testalter_tbl MODIFY i INT NOT NULL; mysql> ALTER TABLE testalter_tbl ADD PRIMARY KEY (i); 你也可使用 ALTER 命令删除主键: mysql> ALTER TABLE testalter_tbl DROP PRIMARY KEY; 删除指定时只需指定PRIMARY KEY,但在删除索引时,你必须知道索引名。
显示索引信息
mysql> SHOW INDEX FROM table_name\G
pymysql为第三方模块,可使用pip install pymysql安装。使用该模块能够在Python中链接MySQL并执行原生SLQ命令。
pymysql使用实例
MySQL中存在testdb数据库,数据库中有表student,表的具体信息以下
+----+--------+----------+ | id | name | class_id | +----+--------+----------+ | 2 | gougou | 1 | | 3 | maomao | 2 | | 4 | tutu | 1 | | 6 | guigui | 2 | +----+--------+----------+
查询数据
import pymysql # 建立链接 conn = pymysql.connect(host="IP", port=3306, user="用户名", password="密码", db="testdb") # 建立游标,相似登陆MySQL后命令提示符的光标 cursor = conn.cursor() # 执行SQL,并返回受影响行数 effect_line = cursor.execute("select * from student") # 读取第一行数据 res1 = cursor.fetchone() # 读取前n行数据 res2 = cursor.fetchmany(2) # 读取所有数据 res3 = cursor.fetchall() # 相似MySQL事务,提交后才执行 conn.commit() # 关闭游标和链接 cursor.close() conn.close() print("%s条记录受影响" % effect_line) print(res1) print(res2) print(res3) #结果 4条记录受影响 (2, 'gougou', 1) ((3, 'maomao', 2), (4, 'tutu', 1)) # 注意:前面已读取一行,这里就从第二行开始 ((6, 'guigui', 2),) # 注意:前面的数据已读取,这里只读取了最后一行
注:在fetch数据时按照顺序进行,可使用cursor.scroll(num,mode)来移动游标位置,如:
添加和修改数据
import pymysql conn = pymysql.connect(host="IP", port=3306, user="用户名", password="密码", db="testdb") cursor = conn.cursor() effect_line1 = cursor.execute("update student set name='wangwang' where id=%s", (2,)) # 一次执行多条 effect_line2 = cursor.executemany("insert into student (name,class_id) values (%s, %s)", [("niuniu", 1), ("yangyang", 2)]) conn.commit() cursor.close() conn.close() print("%s条记录受影响" % effect_line1) print("%s条记录受影响" % effect_line2) #结果 1条记录受影响 2条记录受影响 #执行后的student表 +----+----------+----------+ | id | name | class_id | +----+----------+----------+ | 2 | wangwang | 1 | | 3 | maomao | 2 | | 4 | tutu | 1 | | 6 | guigui | 2 | | 7 | niuniu | 1 | | 8 | yangyang | 2 | +----+----------+----------+
获取自增的新ID
# Life is short,you need Python! import pymysql conn = pymysql.connect(host="IP", port=3306, user="用户名", password="密码", db="testdb") cursor = conn.cursor() cursor.execute("insert into student (name, class_id) values ('yaya', 2)") conn.commit() cursor.close() conn.close() # 获取自增的新ID new_id = cursor.lastrowid print(new_id) #结果 9
以字典形式返回数据
import pymysql conn = pymysql.connect(host="IP", port=3306, user="用户名", password="密码", db="testdb") # 游标设置为字典类型 cursor = conn.cursor(cursor=pymysql.cursors.DictCursor) cursor.execute("select * from student") res = cursor.fetchone() conn.commit() cursor.close() conn.close() print(res) #结果 {'id': 2, 'name': 'wangwang', 'class_id': 1}
什么是ORM
ORM英文全称为object relational mapping,对象映射关系程序,对于面向对象的编程语言来讲一切皆对象,但数据库倒是关系型的,为了保证一致的使用习惯,经过ORM将编程语言的对象模型和数据库的关系模型创建映射关系,这样在使用编程语言对数据库进行操做的时候能够直接使用编程语言的对象模型,而不用直接使用SQL语言。
ORM的优势:
ORM的缺点:
无可避免的,自动化意味着映射和关联管理,代价是牺牲性能(在早期这是全部不喜欢ORM人的共同点)。如今的各类ORM框架都在尝试使用各类方法来减轻这块,效果仍是很显著的。
SQLAlchemy安装
在Python中,最有名的ORM框架是SQLAlchemy。它是一个第三方模块,可使用pip install sqlalchemy安装。
SQLAlchemy基本使用
建立一个表
from sqlalchemy import create_engine from sqlalchemy import Column, Integer, CHAR from sqlalchemy.ext.declarative import declarative_base # 链接数据库 engine = create_engine("mysql+pymysql://用户名:密码@IP/testdb", encoding="utf-8", echo=True) Base = declarative_base() # 生成ORM基类 class Student(Base): __tablename__ = "student" # 表名 id = Column(Integer, primary_key=True) name = Column(CHAR(32), nullable=False) # 建立变长字符串使用String,nullable=False为该字段不能为空 Base.metadata.create_all(engine) # 建立表结构
另外一种方法建立一个表
from sqlalchemy import Table, MetaData, Column, Integer, CHAR from sqlalchemy.orm import mapper metadata = MetaData() student = Table("student", metadata, Column("id", Integer, primary_key=True), Column("name", CHAR(32), nullable=False)) class Student(object): def __init__(self, name): self.name = name mapper(Student, student)
事实上,第一种建立方法就是第二种方法的再封装。
SQLAlchemy支持中文
engine = create_engine("mysql+pymysql://用户名:密码@IP/testdb?charset=utf8", encoding="utf-8")
插入记录到表
from sqlalchemy.orm import sessionmaker SessionClass = sessionmaker(bind=engine) # 建立与数据库的会话,这里返回的是一个class Session = SessionClass() # 生成session的实例 obj1 = Student(name="gougou") # 须要插入的记录 obj2 = Student(name="maomao") Session.add(obj1) # 将记录插入数据库,注意,这里尚未真正写到数据库中 Session.add(obj2) Session.commit() # 统一提交给数据库
此时在MySQL中查询student表,结果以下:
+----+--------+ | id | name | +----+--------+ | 1 | gougou | | 2 | maomao | +----+--------+
SQLAlchemy查询、修改、删除记录
data = Session.query(Student).filter_by(name="gougou").first() # 查询第一条记录 print(data) #结果 <__main__.Student object at 0x00000196737E7C50> #返回的数据映射成一个对象,直接打印即为该对象的内存地址 #能够像调用对象的属性同样调用字段 data = Session.query(Student).filter_by(name="gougou").first() # 查询第一条记录 print("查询出的记录ID:%s,记录内容:%s" % (data.id, data.name)) #结果 查询出的记录ID:1,记录内容:gougou
为了是查询结果变得更加可读,可以使用下面的方法:
from sqlalchemy import create_engine from sqlalchemy.orm import sessionmaker from sqlalchemy import Column, Integer, CHAR from sqlalchemy.ext.declarative import declarative_base engine = create_engine("mysql+pymysql://用户名:密码@IP/testdb", encoding="utf-8") Base = declarative_base() class Student(Base): __tablename__ = "student" id = Column(Integer, primary_key=True) name = Column(CHAR(32), nullable=False) def __repr__(self): return "ID:%s,name:%s" % (self.id, self.name) SessionClass = sessionmaker(bind=engine) Session = SessionClass() data = Session.query(Student).filter_by(name="gougou").first() # 查询第一条记录 print(data) #结果 ID:1,name:gougou
查询全部记录
data = Session.query(Student.id, Student.name).all() print(data) #结果 [(1, 'guigui'), (2, 'maomao'), (3, 'niuniu'), (4, 'gougou'), (5, 'tutu')]
多条件查询
data = Session.query(Student).filter(Student.id > 1).filter(Student.id < 5).all() print(data) #结果 [ID:2 NAME:maomao, ID:3 NAME:niuniu, ID:4 NAME:gougou]
经常使用查询语法
等于
data = Session.query(Student).filter(Student.name == "niuniu").all() print(data) #结果 [ID:5 NAME:niuniu]
不等于
data = Session.query(Student).filter(Student.name != "niuniu").all() print(data) #结果 [ID:1 NAME:gougou, ID:2 NAME:maomao, ID:3 NAME:guigui, ID:4 NAME:tutu]
like
data = Session.query(Student).filter(Student.name.like("%i%")).all() print(data) #结果 [ID:3 NAME:guigui, ID:5 NAME:niuniu]
in、not in
#in data = Session.query(Student).filter(Student.name.in_(["a", "niuniu"])).all() print(data) #结果 [ID:5 NAME:niuniu] #not in data = Session.query(Student).filter(~Student.name.in_(["gougou", "maomao", "niuniu"])).all() print(data) #结果 [ID:3 NAME:guigui, ID:4 NAME:tutu]
null,not null
#null data = Session.query(Student).filter(Student.name.is_(None)).all() print(data) #结果 [] #not null data = Session.query(Student).filter(Student.name.isnot(None)).all() print(data) #结果 [ID:1 NAME:gougou, ID:2 NAME:maomao, ID:3 NAME:guigui, ID:4 NAME:tutu, ID:5 NAME:niuniu]
and
from sqlalchemy import and_ data = Session.query(Student).filter(and_(Student.id == 1, Student.name == "gougou")).all() print(data) #另外一种写法 data = Session.query(Student).filter(Student.id == 1).filter(Student.name == "gougou").all() print(data)
or
data = Session.query(Student).filter(or_(Student.name == "niuniu", Student.name == "gougou")).all() print(data)
filter与filter_by的区别
data = Session.query(Student).filter_by(name="gougou").all() data = Session.query(Student).filter(Student.name == "gougou").all()
修改
data = Session.query(Student).filter_by(name="gougou").first() # 查询出该条记录 data.name = "guigui" # 修改该记录的字段的值 Session.commit()
删除
data = Session.query(Student).filter_by(id=5).first()
Session.delete(data)
Session.commit()
回滚
Session.rollback()
统计
data = Session.query(Student).filter(Student.name.like("%i%")).count() print(data)
分组
from sqlalchemy import func data = Session.query(func.count(Student.name), Student.name).group_by(Student.name).all() print(data) #结果 [(1, 'gougou'), (1, 'guigui'), (1, 'maomao'), (1, 'niuniu')]
SQLAlchemy外键关联
建立classes和student两个表,其中student表的class_id字段关联class表中的id字段。
from sqlalchemy import create_engine from sqlalchemy.orm import sessionmaker, relationship from sqlalchemy.ext.declarative import declarative_base from sqlalchemy import Column, Integer, CHAR, ForeignKey engine = create_engine("mysql+pymysql://用户名:密码@IP/testdb", encoding="utf-8") Base = declarative_base() class Classes(Base): __tablename__ = "classes" id = Column(Integer, primary_key=True) name = Column(CHAR(32), nullable=False) def __repr__(self): return "Class:%s" % self.name class Student(Base): __tablename__ = "student" id = Column(Integer, primary_key=True) name = Column(CHAR(32), nullable=False) class_id = Column(Integer, ForeignKey("classes.id"), nullable=False) # 在class表中经过backref字段反向查询出全部在student表中的关联项 student = relationship("Classes", backref="students") def __repr__(self): return "ID:%s NAME:%s" % (self.id, self.name) Base.metadata.create_all(engine) SessionClass = sessionmaker(bind=engine) Session = SessionClass() classes = ["animal1", "animal2"] for i in classes: Session.add(Classes(name=i)) students = {"gougou": 1, "maomao": 1, "guigui": 1, "niuniu": 2, "tutu": 2} for j in students: Session.add(Student(name=j, class_id=students[j])) Session.commit()
经过class查询相应的student记录
data = Session.query(Classes).all() for i in data: print(i, i.students)
data = Session.query(Classes).filter_by(id=1).all() for i in data: print(i.students)
经过student查询class记录
data = Session.query(Student).all() for i in data: print(i, i.student.name)
多外键关联
建立classes和student表,其中student表中的class_id字段与class_name字段关联classes表中的id字段
class Classes(Base): __tablename__ = "classes" id = Column(Integer, primary_key=True) name = Column(CHAR(32), nullable=False) class Student(Base): __tablename__ = "student" id = Column(Integer, primary_key=True) name = Column(CHAR(32), nullable=False) class_id = Column(Integer, ForeignKey("classes.id"), nullable=False) class_name = Column(Integer, ForeignKey("classes.id"), nullable=False) students = relationship("Classes", foreign_keys=[class_id]) team = relationship("Classes", foreign_keys=[class_name])
SQLAlchemy多对多关系
实例
设计一个能描述图书与做者关系的表结构,需求以下:
此时能够经过中间表来完成书与做者之间的多对多关联
建立book,author,book_to_author三张表
from sqlalchemy import create_engine from sqlalchemy.orm import relationship, sessionmaker from sqlalchemy.ext.declarative import declarative_base from sqlalchemy import Table, Column, Integer, CHAR, ForeignKey engine = create_engine("mysql+pymysql://用户名:密码@IP/testdb?charset=utf8", encoding="utf-8") Base = declarative_base() book_to_author = Table("book_to_author", Base.metadata, Column("book_id", Integer, ForeignKey("book.id")), Column("author_id", Integer, ForeignKey("author.id"))) class Book(Base): __tablename__ = "book" id = Column(Integer, primary_key=True) name = Column(CHAR(64), nullable=False) authors = relationship("Author", secondary=book_to_author, backref="books") def __repr__(self): return "Book Name:%s" % self.name class Author(Base): __tablename__ = "author" id = Column(Integer, primary_key=True) name = Column(CHAR(32), nullable=False) def __repr__(self): return "Author Name:%s" % self.name Base.metadata.create_all(engine) SessionClass = sessionmaker(bind=engine) Session = SessionClass() book1 = Book(name="Python核心编程") book2 = Book(name="Linux内核") a1 = Author(name="aaa") a2 = Author(name="bbb") a3 = Author(name="ccc") a4 = Author(name="ddd") a5 = Author(name="eee") book1.authors = [a1, a2, a3] book2.authors = [a4, a5] Session.add_all([book1, book2, a1, a2, a3, a4, a5]) Session.commit()
MySQL中建立如下三张表。
#author +----+------+ | id | name | +----+------+ | 1 | aaa | | 2 | bbb | | 3 | ccc | | 4 | ddd | | 5 | eee | +----+------+ #book +----+--------------------+ | id | name | +----+--------------------+ | 1 | Python核心编程 | | 2 | Linux内核 | +----+--------------------+ #book_to_author +---------+-----------+ | book_id | author_id | +---------+-----------+ | 1 | 1 | | 1 | 2 | | 1 | 3 | | 2 | 4 | | 2 | 5 | +---------+-----------+ #book_to_author为ORM自动建立自动维护
查询
print("经过书名查做者".center(50, "*")) authors = Session.query(Book).filter(Book.name == "Python核心编程").all() for i in authors: print(i, i.authors, "\n") print("经过做者查书名".center(50, "*")) books = Session.query(Author).filter(Author.name == "aaa").all() for j in books: print(j, j.books) #结果 *********************经过书名查做者********************** Book Name:Python核心编程 [Author Name:aaa, Author Name:bbb, Author Name:ccc] *********************经过做者查书名********************** Author Name:aaa [Book Name:Python核心编程]
删除
author = Session.query(Author).filter(Author.name == "aaa").all() Session.delete(author[0]) Session.commit() #此时ORM自动从book_to_author中删除对应的关联关系