在第二十五章《数据分析的图形化》中所引用的数据源,它记录了不同月份销售量,可以用Python读取、修改和写入。这也就是说,文本可以保存数据。但文本中的数据不是结构化的,数据的查询、检索、修改等一系列的操作都是非常麻烦的,将大量的数据用文本的形式去存储和管理是不科学、也是不现实的。
我们现在通常都是关系型数据库来存储和管理数据,它的数据组织形式类似于一张二维表,如前所述的Excel表(如第十八章《用Python操作Excel文件》中所用到的student.xlsx),也可以将其存储于数据库中。各种数据库都有自己的一套完整的命令用于管理数据库中的数据,但一般用户并不适合直接去操作数据库,因为要掌握一些命令的格式和用法。如果通过应用程序去管理数据库,那么普通用户也可以很方便的获取数据库中的数据,完成各种操作。
数据库的种类很多,但像SqlServer、Oracle这些大型数据库并不适合初学者,而MySQL非常是适合初学者的。而且,不管是大型数据库,还是轻量级的数据库,它们的的操作命令也是基本相同的,都是基于SQL语法规则的。
非常值得欣慰的是,Python自带了一个非常灵巧又实用的数据库——SQLite,它是嵌入式的数据库,只要安装了Python,就可以直接使用SQLite,不需要额外的下载、安装和配置数据库,而数据库的连接也是极为方便,和导入一个普通的模块、创建一个普通的对象没有什么区别。
如果对数据库的操作需求较为简单的,仅仅是创建数据库、添加信息、查看信息、修改信息、删除信息等,那么使用SQLite就够用了。下面先就SQLite中的这些操作作一介绍。
28.1关于数据库
如果你对数据库的知识一无所知,可以先把数据库简单粗暴地类比成一个Excel文件。我们知道,一个Excel文件即一个工作簿,是由若干个表构成的。一个数据库文件中也是由若干表构成的。但不同之处在于,Excel的表中数据是不受约束的,比如同一列,即便是该列的标题为出生年月,但实际上你输入任何类型的数据,哪怕是电话号码都能够保存,但在数据库的表中,一个列(被称为字段或键)必须是同一数据类型的,不符合该类型的数据能被强制转换的,将被强制转换,不能被强制转换的就会发出错误警告。Excel的表中一行的数据可多可少,每一个单元格都是独立的;而数据库的表中的每一行(被称为记录),它对应的每一个字段都是有意义的,即便是没有数据,也要标识为空,每个记录还可以有唯一标识它的字段(或键),被称为关键字段(或主键)。
下面以下表student.xlsx(表28-1)为例进行探讨。
表28-1大家可能注意到了,表28-1和第十八章的表18-1相比,行数减少了,这是为了减少输入量。更为重要的是,列也少了“序号”、“年级”、“班级”、“总分”、“名次”等五列,这可能是Excel表与数据库中表的最大不同,在数据库中,有一个非常重要的思想就是“减少冗余”,能够根据其它字段得到的数据,一般都不增加用于存储该数据的多余字段,这样做,一则可以使数据库“瘦身”,二则可以防止因为计算错误、输入错误等造成“数据的不一致”。既然“学号”中已经包含了“年级”和“班级”的信息,自然就没有必要单独设置这两个字段。同样的,也没有必要设置“总分”和“名次”字段,因为它们都是可以根据“语文”、“数学”、“英语”去计算得到,在具体的程序中增加中间变量就可以了。
28.1创建数据库文件
下面通过实例去学习。首先,我们建立一个名称为student.db的数据库。然后执行SQL语句创建一个名为score的用户表,该表包含“学号”、“姓名”、“语文”、“数学”、“英语”等五个字段,其中“学号”字段非常重要,可以唯一标明一条记录(即唯一的一名学生的信息),必须设置为关键字段(主键),其它各字段都是普通字段。但需要特别注意的是,每个字段都属于固定的数据类型。字段的常用数据类型有如下这几种:
varchar(n)字符,表示最大长度
boolean布尔型,值为
integer整数值
numeric精确数值,精度
float浮点数
date存储年、月、日的值。
time存储小时、分、秒的值。
存储
下面代码可以创建student.db数据库和score表:
import sqlite3
# 导入sqlite3模块
conn=sqlite3.connect('student.db')
# 建立数据库连接conn,连接数据库student.db。若不存在该数据库,则在当前路径下创建。
cursor=conn.cursor()
# 创建游标cursor
cursor.execute('create table score (Sn varchar(6),Name varchar(4),Chn numeric(5,1),Math numeric(5,1),En numeric(5,1),primary key(Sn))')
# 执行一条SQL语句,创建数据表score,Sn为关键字段(主键)。
cursor.close()
# 关闭游标
conn.close()
# 关闭连接
至此,数据库student.db数据库及其下的score表就建立完成了,当然,此时的score表还是个只有表结构(仅定义了字段)而无记录的空表。
如果要查看数据表score的表结构信息,其它数据库系统中常用的show columns语句和describe语句在SQLite中并不适用,只能改用如下方法去查看(这里所用到的查询语句后面会讲到):
import sqlite3
conn=sqlite3.connect('student.db')
cursor=conn.cursor()
cursor.execute('select * from sqlite_master where type="table" and name="score"')
result=cursor.fetchall()
print(result)
cursor.close()
conn.close()
运行结果如下:
[('table', 'score', 'score', 2, 'CREATE TABLE score (Sn varchar(6),Name varchar(4),Chn numeric(5,1),Math numeric(5,1),En numeric(5,1),primary key(Sn))')]
可以看到建立此表时的语句内容,表明一个数据表已经建立完成了。
关于游标
数据库中的游标相当于指针,可以借助游标访问一行或多行数据。SQL命令的执行大都依附于游标来完成。现在无需理解的更加清楚,只要知道游标就是访问数据库的工具就可以了。
关于CREATE语句
语法格式:
CREATE TABLE [IF NOT EXISTS] 数据表名 (列名 数据类型,列名 数据类型,......,[AUTO_INCTEMENT][PRIMARY KEY(列名)])
其中,IF NOT EXISTS表示先检查该数据库中是否有同名的表存在,如果没有则新建;AUTO_INCTEMENT表示该列可以自动编号,但若选此项则必须该列被索引;PRIMARY KEY(列名)表示将该列定义为主键。
28.2追加记录
追加记录命令的语法格式:
INSERT INTO 表名(列名1,列名2,......,列名n)VALUES (列值1,列值2,......,列值n)
28.3查询记录
查询记录命令的语法格式:
SELECT 列名1,列名2,......,列名n FROM 表名 WHERE 查询条件
获取查询结果时,还需要用到游标的fetch方法,而fetch有三种形式:
fetchone():可以获取查询结果集中的一条记录
fetchmany(size):可以获取查询结果集中指定数量的记录
fetchall():可以获取查询结果集中所有的记录
下面例子可以向数据表score添加记录并进行查询:
import sqlite3
conn=sqlite3.connect('student.db')
cursor=conn.cursor()
cursor.execute('insert into score (Sn,Name,Chn,Math,En) values("070101","王博宇","84","71","93")')
cursor.execute('insert into score (Sn,Name,Chn,Math,En) values("070102","陈冠涛","89","89","89")')
cursor.execute('insert into score (Sn,Name,Chn,Math,En) values("070103","李文博","89","72","76")')
cursor.execute('insert into score (Sn,Name,Chn,Math,En) values("070204","姜海燕","89","89","89")')
cursor.execute('insert into score (Sn,Name,Chn,Math,En) values("070205","林若溪","91","95","83")')
#以上语句向score表中追加了5条记录
cursor.execute('select * from score')
#执行查询语句
result1=cursor.fetchone()
print(result1)
result2=cursor.fetchmany(2)
print(result2)
result3=cursor.fetchall()
print(result3)
cursor.close()
conn.close()
运行结果:
('070101', '王博宇', 84, 71, 93)
[('070102', '陈冠涛', 89, 89, 89), ('070103', '李文博', 89, 72, 76)]
[('070204', '姜海燕', 89, 89, 89), ('070205', '林若溪', 91, 95, 83)]
从运行结果可以看出,select * from score 语句返回的结果集是score表的全部记录,result1得到的第一条记录,result2得到的第二、三条记录,result3得到的是剩下的全部记录。可见游标是在向后移动的。
SELECT语句可以按照条件进行查询,如:
cursor.execute('select * from score where Chn>=80 and Math>=80 and En>=80')
可以得到各科成绩都不低于80分的学生的信息。
也可以查询部分字段的信息,如
name
可以查询到所有语文成绩不低于80分的学生的姓名。
28.4修改记录
修改记录命令的语法格式:
UPDATE 表名 SET 字段名=字段值 WHERE 查询条件
如下这两种语句都可以修改Sn=‘’的学生的信息:
cursor.execute('update score set Chn=90 where Sn="070101"')
cursor.execute('update score set Chn=? where Sn=?',(88,"070101"))
28.5删除记录
删除记录命令的语法格式:
DELETE FROM 表名 WHERE 查询条件
如下这两种语句都可以删除Sn=‘’的学生的信息:
cursor.execute('delete from score where Sn="070101"')
cursor.execute('delete from score where Sn=?',("070101",))
当然,SQLite数据库实在有些太简陋了,就连像“删除多余字段”这样的命令都没有提供,真的严重影响用户的心情。
