Note: XLY23333
RAW Video: check
Python Version: 3.11
SQL基础操作可参考文章:
[CSDN] SQL Basic VERSION1
[CSDN] SQL Basic VERSION2
即SQL(Structured Query Language)语法
开源、嵌入式关系型数据库引擎,其数据库就是一个db文件,直接存放在本地
Python3内嵌SQLite,无需再安装,只需要通过sqlite3模块驱动
SQLite使用一个更普遍的动态类型系统。在SQLite中,值得数据类型与值本身是相关的,而不是与它的容器相关
SaveType | Description |
---|---|
NULL | 空值 |
INTEGER | 带符号的整数,根据值大小存储(6种不同长度类型) |
REAL | 浮点值,存储为8字节的IEEE浮点数 |
TEXT | 文本字符串,使用数据库编码(UTF-8/UTF-16BE/UTF-16LE) |
BLOB | 二进制数据,完全根据输入存储 |
⚠️:SQLite3同样支持SQL标准数据类型(如varchar), 但更推荐使用更普遍的动态类型系统
COde:
后续INSERT时可以省略id传入,但是需要使用指定行的方法INSER
INSERT INTO <TableName> (
<Col1, Col2, ...>
)VALUES(
(?, ?, ...)
)
插入新类别之后,可通过category_id = c.lastrowid
获取新插入的类别ID
写在外键后面的内容,用于确定级联操作
Format:
CREATE TABLE <TableName>(
<ColName1> <DataType> <Addition>,
<ColName2> <DataType> <Addition>,
<ColName3> <DataType> <Addition>,
...
<ColNameN> <DataType> <Addition>,
FOREIGN KEY (<ColName>) REFERENCES <OtherTableName> (<ColName>)
ON DELETE/UPDATE <ADDITION>
)
ADDITION:
最常用的操作:
FOREIGN KEY (<ColName>)
REFERENCES <OtherTableName> (<ColName>)
ON DELETE CASCADE -- 级联删除
ON UPDATE SET NULL -- 级联更新
⚠️:外键约束的启用需要在每个数据库连接后立即执行,而不是仅在创建数据库时
即需要在每次连接数据库时执行PRAGMA foreign_keys = ON;
Py操作时则需要在连接数据库后执行conn.execute('PRAGMA foreign_keys = ON')
级联操作会导致数据完整性问题,请慎用!
Python数据库应用DB-API接口
.close()
关闭DB连接.commit()
将未完成的事务提交到数据库.rollback()
将数据库回滚到未完成事务的开始状态.cursor()
在数据库连接上创建一个cursor对象一段私有的SQL工作区,即内存区域,用于暂时存放受SQL语句影响到的数据,可以理解为受影响的数据放置在一个虚表中,虚表即为游标
Method | Description |
---|---|
execute(operation[, parameters]) |
在数据库上执行SQL操作语法(operation: SQL语句字符串),parameters是语句字符串中变量值的序列或映射 |
executemany(operation[, paramseq]) |
执行多条SQL命令,将每条命令所需的变量值存储在parameq序列中 |
Method | Description |
---|---|
fetchone() |
返回查询数据库后得到下一行的结果集(List/Tuple) |
fetchmany([size]) |
返回查询结果行的序列,可选参数size代表行数 |
fetchall() |
返回全部剩余的查询结果行的序列 |
nextset() |
跳到下一结果集,准备获取其信息 |
Property | Description |
---|---|
arraysize |
为fetchmany()方法提供的默认整数值,表示一次返回结果集行数 |
description |
返回当前集的列名信息 |
rowcount |
返回查询结果的行数,-1表示没有结果集 |
以存储书为例,DB包括两个表:category(记录分类)和book(记录书籍信息)
一本书归属于某个分类因此book有一个外键(foreign key),指向category表的主键id
Python Code:
import os
import sqlite3 # SQLite3模块
def CreateTable():
# 创建连接数据库
DB_PATH = os.path.join(os.path.dirname(os.getcwd()), 'DB', 'demoDB.db')
# print(DB_PATH)
conn = sqlite3.connect(DB_PATH)
# 创建游标
c = conn.cursor()
# CREATE TABLE
'''
设置id为递增INTEGER主键
Book表的category外键连接到category表的id列
'''
table1_sql = '''
CREATE TABLE category(
id INTEGER PRIMARY KEY AUTOINCREMENT,
sort INTEGER,
name TEXT
)
'''
c.execute(table1_sql)
table2_sql = '''
CREATE TABLE book(
id INTEGER PRIMARY KEY AUTOINCREMENT,
sort INTEGER,
name TEXT,
price REAL,
category INTEGER,
FOREIGN KEY (category) REFERENCES category(id)
ON DELETE CASCADE
ON UPDATE CASCADE
)
'''
c.execute(table2_sql)
# 提交事务 save the changes
conn.commit()
# 在已经建成的表当中插入新列
c.execute('ALTER TABLE category ADD COLUMN score TEXT NULL')
conn.commit()
# 关闭连接
conn.close()
print("[INFO] Success CREATE DB")
Python Code:
def InsertData():
# 创建连接数据库
DB_PATH = os.path.join(os.path.dirname(os.getcwd()), 'DB', 'demoDB.db')
conn = sqlite3.connect(DB_PATH)
c = conn.cursor()
# 准备数据
'''
由于使用了递增INTEGER主键, 可以不导入id, 但是INSERT不可省略列信息
'''
bookls = [
(1, 'Python入门', 88.8, 1),
(3, 'Java入门', 99.9, 2),
(2, 'C++入门', 120.0, 1),
(4, 'C#入门', 150.0, 2),
(5, 'Ruby入门', 180.0, 1),
(8, 'PHP入门', 200.0, 2),
(7, 'JavaScript入门', 220.0, 1),
(6, 'Swift入门', 250.0, 2),
(9, 'Kotlin入门', 280.0, 1),
(10, 'Go入门', 300.0, 2),
]
# SQL语句提交数据
## 单句SQL执行
c.execute('INSERT INTO category (sort, name) VALUES (1, "Normal")')
## 使用?占位导入list/Tuple数据
c.execute('INSERT INTO category (sort, name) VALUES (?, ?)',
[2, "WEB"])
## 多句SQL执行
c.executemany('INSERT INTO book (sort, name, price, category) VALUES (?, ?, ?, ?)',
bookls)
conn.commit()
conn.close()
print("[INFO] Success INSERT INFO")
Python Code:
def SelectData():
DB_PATH = os.path.join(os.path.dirname(os.getcwd()), 'DB', 'demoDB.db')
conn = sqlite3.connect(DB_PATH)
c = conn.cursor()
# 按sort排序查询sort第一的书名
c.execute('SELECT name FROM book ORDER BY sort')
print('===SORT SELECT ONE===\n',
c.fetchone())
# 查询所有category=2的所有book信息
c.execute('SELECT * FROM book WHERE category=1')
print('===WHERE SELECT ALL===\n',
c.fetchall())
# 迭代用法
print('===iter SELECT===')
for row in c.execute('SELECT name, price FROM book ORDER BY sort'):
print(row)
## 使用JOIN方法查询对应外键
foreign_sql = '''
SELECT book.name, category.name, book.price
FROM book
JOIN category ON book.category = category.id
ORDER BY book.price DESC
'''
c.execute(foreign_sql)
print('===FOREIGN JOIN ON SELECT===\n',
c.fetchall())
conn.close()
SQL Code:
-- 选择书名、分类名、书价列
SELECT book.name, category.name, book.price
-- 从book表中
FROM book
-- JOIN合并book、category表
JOIN category
-- 合并条件:两者属性相等
ON book.category = category.id
-- 条件: book的category属性=2
WHERE book.category=2
-- 排序:倒序按书本价格排序
ORDER BY book.price DESC;
Tips:
c.execute('SELECT * FROM sqlite_master WHERE type="table"')
c.execute('PRAGMA table_info(tableName)')
Python Code:
def _showdata(DB_path, sql_cmd:str = None):
conn = sqlite3.connect(DB_path)
c = conn.cursor()
c.execute(sql_cmd)
info = c.fetchall()
conn.close()
print(info)
return info
def DeleteData():
DB_PATH = os.path.join(os.path.dirname(os.getcwd()), 'DB', 'demoDB.db')
conn = sqlite3.connect(DB_PATH)
c = conn.cursor()
conn.execute('PRAGMA foreign_keys = ON') # 启用外键约束
# 新增新类别food
c.execute('INSERT INTO category (sort, name) VALUES (?, ?)', (3, 'food'))
category_id = c.lastrowid # 获取新插入的类别ID
print(f'Last Row ID: {category_id}')
# 新增书food1~5
foodls = [
(1, '西红柿炒鸡蛋', 10.0, category_id),
(2, '香菇炒鸡蛋', 15.0, category_id),
(3, '豆腐煎蛋', 20.0, category_id)
]
c.executemany('INSERT INTO book (sort, name, price, category) VALUES (?, ?, ?, ?)',
foodls)
conn.commit()
print('===INSERT DATA===')
_showdata(DB_PATH, 'SELECT * FROM category')
_showdata(DB_PATH, ''' SELECT book.name, book.price, category.name
FROM book
JOIN category
ON book.category=category.id
ORDER BY book.price DESC
''')
# 删除新类别food
c.execute('DELETE FROM category WHERE name="food"')
conn.commit()
print('===DELETE DATA===')
_showdata(DB_PATH, 'SELECT * FROM category')
_showdata(DB_PATH, ''' SELECT book.name, book.price, category.name
FROM book
JOIN category
ON book.category=category.id
ORDER BY book.price DESC
''')
conn.close()