1.数据库是什么
我们可以通过文本文件,json文件,csv,xls文件来保存数据,但是如果项目数据量比较大,会涉及到不同平台或程序,或语言框架交换的话,前面讲的以文件存储就不合适。
这时需要数据库来做
很多数据放在一起就形成了一张表,多张表包括其他的数据库对象存储到数据库里面。
数据——表+视图+存储过程+触发器,这些对象——数据库
整个一套叫做DBS,Database Syste,数据库系统

举例说明:
要找一本书,有书的ISBN编号,标题,定价,作者,出版社,如下面的一条记录:

称之为一条记录
如果有很多行,就构成了二维表,上面还有表头

现在看到的,竖着的为列,横着的叫行,一行就是一条数据,一列表示信息或一个属性。
发现,定价/作者/日期都有自己的类型,就像再python中写程序一样,一个字段或一个变量是有类型的,比如pubdate的类型是时间型,Author是字符串,Price是float,这样在创建这样一个表结构,插入数据库之前,就要将其确定下来。
用SQLite创建一个表,插入测试数据。
演示:SQL语言基本的查询操作,然后将重点放到python里面。同样的数据库,在python中怎么做
SQLite数据库是基于文件的,管理方便,随便找一个SQLite管理的gui(桌面程序),或者不用SQLite,直接使用python。pycharm里面也能管理。
比如用SQLite Expert Professional软件
假定要创建一张表,来保存通讯录,存到数据库中
数据库是基于文件的,所以先创建一个文件,后为…db/…db3/sqlite3,都可以。
new database,创建数据库

Database Creation Propertiies数据库创建属性
Database Files:数据库文件位置
Database Alias:数据库化名 alias(文件/互联网地址用的)别名
Encoding

同时在pycharm中创建一个项目,db文件,将数据库文件放这里

Database Creation Propertiies中:
Database Files:数据库文件位置,找到刚才创建的db文件中,取名addressbook,常见后缀有三个,现在将其后缀取为.db

这个库的位置就在这里了,

OK,库创建好了
出现一个设计器,Design
要填Table name,表名:linkman
字段,点添加,Add,
New field
Nmae
Type
Size
Not null:不允许为空,打上

这里要注意:别的数据库系统都是静态类型,创建表时先定义好,以后再插入数据,必须要遵循这一套类型系统,但是SQLite是动态类型。
创建字段时,字段数据类型type很多,因为它把其他数据库类型也列出来了。
建议写为自己熟悉的类型,这样便于以后迁移或移植,
Size:其他数据库定下这个20后,后面填入长度超过20会报错,但是SQLite超过20也会正常显示,因为是动态类型。
最后创建了四个字段

如何区分这些标识,比如会加int型ID,SQLite已经准备好了一个字段,不用自己手动添加,会自动添加, 叫Row ID,可以获得一个整形的唯一标识
共有5个字段,便于标识数据唯一性
点apply应用
添加完之后,addressbook数据库下面有一个linkman表,默认是隐藏的

现在要对表进行维护,用SQL语句查询
SELECT * FROM LinkMan #选择字段,所有的用星号*。从LinkMan表中选出所有行所有列字段。
SELECT * FROM LinkMan
INSERT INTO LinkMan () value ('Tom','15600098999','1990-09-01',1) #插入表中列(),所有列,省略列名,值,不省就写全(Name,Mobile,BirthDate,IsValid).
# 姓名是文本型,用单引号,不能像python,既可以单引号也可以双引号。
#生日日期,时间加单引号
# 数据库中true是1,false是0.int型不加单引号,数值型不加单引号
INSERT INTO LinkMan () value ('Jerry','15600098999','1990-09-01',1)
INSERT INTO LinkMan () value ('Mike','15600098999','1990-09-01',1)
INSERT INTO LinkMan () value ('Peter','15600098999','1990-09-01',1)
INSERT INTO LinkMan () value ('Matrry','15600098999','1990-09-01',1)
注意最下面,1 row affected,1 total,是指一行受影响/受影响的行数是1.即:改变了一行

第一条已经插入过了,将后4条选中,注意:其他编程语言数据库,多条语句,中间不用分号隔开就能执行,SQLite要加上分号。
选上4条,点执行Execute SQL,就是4 rows affected,5 total,4行受影响,共5条。
比如把第一行的tom的生日更新了
UPDATE LinkMan SET BirthDate = '1988-12-11' WHERE rowid = 1
Execute SQL,结果:1 row affected.
重新查询,结果
SELECT * FROM LinkMan
DELETE FROM LinkMan #这样写LinkMan所有数据都删掉了
DELETE FROM LinkMan WHERE rowid = 5 #加上条件
python内置模块,sqlite3
数据库SQLite中的大部分功能在pycharm中可以搞定

可以看到,工作目录中.db数据库文件已经存在了。
pycharm界面右侧,一个database标签,点进去。
点加号,data source,链接数据源

引擎类型来自sqlite,同时在这里可以发现,pycharm可以连接很多数据源,
连接sqlite

File:文件位置,点右面…按钮,

OK,测试一下,Test Connection,

没有问题

第一次连接时可能会要下载一个驱动。这里已经装好了,所以直接连接成功。OK

这样就可以在pycharm中直接操作了。
数据库中表的信息在这里都能看到

pycharm已经准备好了数据库的操作窗口,这时pycharm专业版自带的功能

先在数据库工作目录下新建脚本db.py

在python中操作,将SQL语句准备好,交给python里的两个对象,执行就可以。返回的数据类型类似于在python中内置的数据结构,比如tuple或list
代码零散,先在console中写,需要封装时再写到db.py中
连接对象是大部分编程语言在连接数据源时都需要的,
是连接对象的方法,conn.cursor,也是一个对象
在python中,写一个SQL语句,放到一个string型的变量中,但是不会执行。得靠一个对象来执行。
在python中执行SQL语句,用游标。
创建对象:
来自于连接对象的一个方法,cursor=conn.cursor()
c = conn.cursor()
c游标带的方法来帮助做工作
游标的方法:
不用fetchall方法,也可以获取,结果是sqlite3.Cursor对象对象,这个对象可遍历。
用fetchall方法,获取所有,结果为list对象。
import sqlite3 #导入sqlite3模块,接下来就可以操作数据库了
conn = sqlite3.connect('db\\addressbook.db') #注意:console不是以db为目录的,是以lesson5为根目录的,所以要连接的数据库文件是来自于db\\addressbook.db.如果是在脚本文件中就不用,因为脚本中的db是跟操作的数据库对象的db是同级的。在脚本中这样写就行,conn = sqlite3.connect('addressbook.db')
#如何知道console的根目录,
c = conn.cursor() #数据库连接搞定,准备好的SQL语句要执行,让c来做。c游标自己带的方法来帮做工作.c现在就是游标对象
sql = 'select * from LinkMan' #写为字符串,这个sql语句不会执行,要通过游标来执行
c.execute(sql) #将sql字符串传进去,就可以执行
result = c.execute(sql)
result #游标执行的结果为sqlite3.Cursor对象,执行结果如下图。不是行或列。但是游标对象如果选择的是多条数据,可以将其想象为python的迭代对象,可以直接遍历。即sqlite3.Cursor对象可以遍历。
for row in result:
print(row)#结果看起来像元组,结果如下图。
# 添加操作。在数据库表中添加内容
sql ="insert into LinkMan values ('Marry','18600098999','1985-03-09',1)" #注意引号,由于变量是字符串,所以加引号。在SQL中表示字面值时,text和datetime值也要加单引号,所以外侧用双引号,里面用单引号。目前写的是SQL语言,但是实际上在python中是字符串,还需要用游标去执行
c.execute(sql) #执行结果如下图
#执行结束后数据没有成功添加进去。
#如果你执行增删改时,调用了,但是没有映射到数据源,这时要调用一个方法commit(),把刚才的操作给提交上去
conn.commit()
conn.close()
# 结果数据添加上了
# 对数据表修改
conn = sqlite.connect('db\\addressbook.db') #刚才conn.close()把与数据库的连接关闭了,现在重新打开
c = conn.cursor() #重新定义conn的游标对象为c
sql = "UPDATE LinkMan SET Mobile='18599990000' WHERE Name='Peter'"
c.execute(sql) #执行上面的string,执行为sql语句
conn.commit() #提交给数据源上面的命令,更改数据表内容结果如下
#删除数据表内容
sql = "DELETE FROM LinkMan WHERE rowid=5"
c.execute(sql)
conn.commit() #执行结果如下
#特殊场景
#提出新需求
sql = "SELECT OID,* FROM LinkMan"
c.execute(sql) #还没有真正获取,用的时候才帮助获取
# 接下来看,选择的是所有对象还是单条对象
# 这里数据量少,可以选所有,游标的方法,lst=c.fetchall() #提取所有交给一个list
lst #结果是列表,列表中包含元组,每个元组是数据表中的每一行
for row in lst:
print(row) #遍历list中,每个元素是一个元组。可以用索引打印出每一元组中的一列。print(row[]).结果如下图
#仅获取一条
sql = "SELECT OID,* FROM LinkMan"
c.execute(sql)
row = c.fetchone() #仅获取一条,只返回数据表中第一条
row #结果见下面的图
# 获取多条
c.execute(sql)
result = c.fetchmany(2) #返回结果为列表,获取2条
result #结果见下图
注意:console不是以db为目录的,是以lessons为根目录的,所以要连接的数据库文件是来自于
如何知道console的根目录:
当启动console时,这里追加了一个扩展路径

如果是在脚本文件中就不用,因为脚本中的db是跟操作的数据库对象的db是同级的。

result = c.execute(sql)
result #游标执行的结果为sqlite3.Cursor对象,执行结果如下图。

for row in result:
print(row)#结果是元组,结果如下图
结果像元组,但不是元组

sql =“insert into LinkMan values (‘Marry’,‘18600098999’,‘1985-03-09’,1)”
c.execute(sql) ,执行结果

执行结束后数据没有成功添加进去
conn.commit()
conn.close()
结果数据添加上了,结果如下图

更改数据表结果如下:

删除数据表内容,结果如下:

lst=c.fetchall() #提取所有交给一个list
结果

for row in lst:
print(row)
结果如下图:
row = c.fetchone() 结果:

result = c.fetchmany(2) 结果

刚才上面的例子为了保持简单,把这些内容都写死了,实际开发中,这些可能来自用户与程序交互的界面。可能是在控制台上读取的,有可能是在网页上读取的,这样,SQL语句就不能写死了。
在console上
# 获取一个人的信息
name = 'Tom' # 从console上读取到
# SQL语句不能写死,将刚才的name用上
sql ="SELECT * from LinkMan WHERE Name='{}'".format(name) # 容易引起sql注入,不推荐这个拼接语句的方法去调用sql语句
sql #结果变为拼接效果。结果如下图
c.execute(sql)
c.fetchone()
sql =“SELECT * from LinkMan WHERE Name=’{}’”.format(name)
结果变为拼接效果


这种方式灵活,符合python习惯,但是容易引起sql注入
name = ('Tom',) #变量写入括号,在后面加上逗号,就是元组
sql = "select * from LinkMan where Name = ?" # ?是sql语句的占位符。?这里之后要来新值
c.execute(sql,name) # 执行sql,但是?这里要来一个新值,这个新值从name这里来。name是一个元组
c.fetchone() #结果如下图
#sql = "insert into LinkMan values (?,?,?,?)" #有四个值要填,写4个问号
# 上面是问号参数,下面是冒号:参数
sql = "insert into LinkMan values (:name,:mobile,:birthdate,:isvalid)"
c.execute(sql,{"name":"john","mobile":"18900009999","birthdate":"1989-09-03",isvalid":1})
conn.commit()
做增删改查操作
用python创建一个脚本文件或写一个类来操作

假定现在要对db目录中的addressbook.db数据库操作,要定义几个函数
import sqlite3
def open_cnn(): #创建和数据库的连接
pass
def close():
pass
def commit(): #提交python操作给数据源
pass
def get_all_linkMan(): #获取/打印所有联系人
pass
def get_LinkMan_by_id():#给定一个id,把联系人获取到
pass
def get_LinkMan_by_name():#根据联系人名称获取
pass
def update_LinkMan(id,data): #更新数据,要传入参数
pass
def dlete_LinkMan_by_id(id):
pass
写这个脚本/类,就可以对通讯录进行管理。将console中的代码移过来