返回介绍

4.2 MySQL 数据库

发布于 2024-01-27 22:10:03 字数 17852 浏览 0 评论 0 收藏 0

要完成本节中的示例代码,需要有 MySQLdb 扩展包,也就是 MySQL-python(Python v2)或 mysqlclient(Python v3)3。这个扩展包可以使 Python 与数据库以及数据表进行交互,所以我们使用它与在本节中创建的 MySQL 数据表进行交互。如果你安装了 Anaconda Python,那么你就已经安装了这个扩展包,因为它与安装程序是捆绑在一起的。如果你是从 Python.org 网站上安装的 Python,那么你需要按照附录 A 中的指导步骤安装这个扩展包。

3这些扩展包可以在 Python Package Index(https://pypi.python.org/pypi/mysqlclient)中找到。

和之前一样,为了使用数据库中的表,必须先创建一个。

(1) 参照附录 A,下载安装 MySQL 数据库系统。

下载安装了 MySQL 数据库系统之后,你就可以使用 MySQL 命令行客户端了。

(2) 在命令行中输入 mysql,打开 MySQL 命令行客户端。

现在你可以使用命令行界面与 MySQL 数据库系统进行交互了。首先,让我们看一下 MySQL 数据库系统中已有的数据库。

(3) 要完成这个操作,输入以下命令,然后按回车键。图 4-10 展示了 Windows 系统下的结果。

SHOW DATABASES;

请注意上面的命令以分号结尾,这样 MySQL 才知道你的命令已经输入完成。如果你没有输入分号就按了回车键,那么 MySQL 会期待你继续输入下一行命令(很快你就会看到多行命令)。如果你忘记了分号,也不要着急,在下一行中输入分号,然后按回车键, MySQL 就会执行你的命令。

这条命令的输出显示,在 MySQL 数据库系统中已经有了 4 个数据库。这些数据库使 MySQL 数据库系统能够运行,并包含系统用户的权限信息。要创建一个数据表,必须先创建一个你自己的数据库。

图 4-10:安装了 MySQL 之后,SHOW DATABASES; 命令显示 MySQL 中的默认数据库

(4) 要创建一个数据库,输入以下命令,然后按回车键:

CREATE DATABASE my_suppliers;

按了回车键之后,你可以再运行一次 SHOW DATABASE; 命令,看一下你刚刚创建的新数据库。要在 my_suppliers 数据库中创建数据表,必须先选择 my_suppliers 数据库。

(5) 要选择 my_suppliers 数据库,输入以下命令,然后按回车键(参见图 4-11):

USE my_suppliers;

图 4-11:创建一个新数据库 my_suppliers,查看已经包括在已有数据库列表中的新数据库,切换数据库并开始使用

按了回车键之后,你就已经选择了 my_suppliers 数据库。现在可以创建数据表来保存供应商数据了。

(6) 要创建一个数据表 Suppliers,输入以下命令,然后按回车键:

CREATE TABLE IF NOT EXISTS Suppliers
(Supplier_Name VARCHAR(20),
Invoice_Number VARCHAR(20),
Part_Number VARCHAR(20),
Cost FLOAT,
Purchase_Date DATE);

如果数据库中不存在数据表 Suppliers,这个命令就创建数据表 Suppliers。这个表有 5 个列(也就是 fields 或 attributes):Supplier_Name、Invoice_Number、Part_Number、Cost 和 Purchase_Date。

前 3 个列是可变字符 VARCHAR 型字段。20 表示为这个字段中的数据分配 20 个字符。如果输入这个字段的数据大于 20 个字符,那么数据将被截断。如果数据少于 20 个字符,那么这个字段就为数据分配一个更小的空间。我们应该为包含变长字符串的字段选择 VARCHAR 类型,因为这样可以使数据表节省保存不必要字符的空间。但是,你必须确定圆括号中的数值足够大,可以分配足够多的字符以保证字段中最长的字符串不被截断。除了 VARCHAR,还有一些其他字段类型,比如 CHAR、ENUM 和 BLOB。当你想设置一个有固定数量的字符的字段,或者需要将字段中的值向右补齐到一个固定长度时,可以考虑 CHAR 字段类型;当字段取值是一个允许值列表(比如 small、medium、large)时,可以考虑 ENUM 类型字段;当字段内容是长度可变的大量文本时,可以考虑 BLOB 类型的字段。

第四列是一个浮点数 FLOAT 字段。浮点数字段保存浮点数近似值。因为在这个例子中,第四列包含的是货币值,所以可以用 NUMERIC 类型字段替代 FLOAT 类型字段,NUMERIC 字段即定点确定值类型字段。例如,不使用 FLOAT,可以使用 NUMERIC(11, 2)。11 是数值的精度,或者是为数值保存的数位总数,包括小数点后面的位数。2 是小数位数,也就是小数点后面的数位总数。在这个例子中,我们使用 FLOAT 而不使用 NUMERIC,是为了获得最大的代码可移植性。

最后一列是一个日期 DATE 字段。DATE 字段用来保存日期,形式为 'YYYY-MM-DD',没有时间部分。所以像 6/19/2014 这样的日期在 MySQL 中被存储为 '2014-06-19'。无效的日期被转换为 '0000-00-00'。

(7) 为了确保数据表创建正确,输入以下命令,然后按回车键:

DESCRIBE Suppliers;

按了回车键之后,你会看到一个表格,其中列出了你创建的列的名称、每列的数据类型(例如:VARCHAR 或 FLOAT)和列中的值是否可以为 NULL。

现在我们已经创建了数据库 my_suppliers 和数据表 Suppliers,还要创建一个新用户,并授予这个用户与数据库和数据表进行交互的权限。

(8) 要创建一个新用户,输入以下命令,然后按回车键(请注意用你要使用的用户名替换 username;你还应该用自己的密码替换 secret_password,来获得更高的安全性):

CREATE USER 'username'@'localhost' IDENTIFIED BY 'secret_password';

我们已经创建了一个新用户,现在要为这个用户授予 my_suppliers 数据库的所有权限。通过授予用户所有的数据库权限,就使这个用户可以在数据库中的表上执行各种操作。这些权限非常有用,因为本节中脚本涉及的操作包括向表中加载数据、修改表中特定记录和对数据表执行查询。

(9) 要向新用户授予所有权限,输入以下两条命令,然后在每条命令后面按回车键(同样,注意用你在前一步创建的用户名替换 username):

GRANT ALL PRIVILEGES ON my_suppliers.* TO 'username'@'localhost';
FLUSH PRIVILEGES;

现在你可以同本地主机(也就是你自己的计算机)中的 my_suppliers 数据库中的 Suppliers 表进行交互了。参见图 4-12。

图 4-12:在 my_suppliers 数据库中创建新表 Suppliers,创建一个新用户,为新用户授予 my_suppliers 数据库和其中的表的所有权限

现在你已经创建了一个数据库和用来保存数据的表,下面就开始学习如何使用 Python 向表中加载数据。

4.2.1 向表中插入新记录

现在我们准备从一个 CSV 文件中将记录加载到数据表中。你已经可以从 Python 脚本或 Excel 文件中将记录输出到 CSV 文件,这可以使你创建一个多用途的数据通道。

下面创建一个新的 Python 脚本。这个脚本会将数据从 CSV 文件中插入到我们的数据表,然后展示表中的数据。其中的第二个步骤,即在命令行窗口或终端窗口打印数据,并不是必须的(而且如果你加载了上千条记录的话,我也不建议将记录打印在窗口中),我之所以在示例中包括了这个步骤,是想演示一种不指定单独的列索引,打印出每条记录中所有列的方法(也就是说,这种语法可以扩展到任意数目的列)。

首先,在文本编辑器中输入下列代码,然后将文件保存为 4db_mysql_load_from_csv.py:

 1 #!/usr/bin/env python3
 2 import csv
 3 import MySQLdb
 4 import sys
 5 from datetime import datetime, date
 6
 7 # CSV输入文件的路径和文件名
 8 input_file = sys.argv[1]
 9 # 连接MySQL数据库
10 con = MySQLdb.connect(host='localhost', port=3306, db='my_suppliers', \
11 user='root', passwd='my_password')
12 c = con.cursor()
13 # 向Suppliers表中插入数据
14 file_reader = csv.reader(open(input_file, 'r', newline=''))
15 header = next(file_reader)
16 for row in file_reader:
17     data = []
18     for column_index in range(len(header)):
19          if column_index < 4:
20               data.append(str(row[column_index]).lstrip('$')\
21               .replace(',', '').strip())
22          else:
23               a_date = datetime.date(datetime.strptime(\
24               str(row[column_index]), '%m/%d/%Y'))
25               # %Y: year is 2015; %y: year is 15
26               a_date = a_date.strftime('%Y-%m-%d')
27               data.append(a_date)
28     print data
29     c.execute("""INSERT INTO Suppliers VALUES (%s, %s, %s, %s, %s);""", data)
30 con.commit()
31 print("")
32 # 查询Suppliers表
33 c.execute("SELECT * FROM Suppliers")
34 rows = c.fetchall()
35 for row in rows:
36     row_list_output =[]
37     for column_index in range(len(row)):
38          row_list_output.append(str(row[column_index]))
39     print(row_list_output)

这个脚本和第 2 章中的脚本一样,依赖于 csv、datetime、string 和 sys 模块。第 2 行代码导入 csv 模块,这样我们就可以使用其中的方法读取和解析 CSV 文件了。第 4 行代码导入 sys 模块,以使我们可以在命令行中提供一个文件的路径和名称供脚本使用。第 5 行代码从 datetime 模块导入 datetime 和 date 方法,以使我们可以对输入文件中最后一列的日期数据进行处理和格式化。这里需要剥离数据中的美元符号,还要删除任何内嵌的逗号,这样数据才能被输入到数据表中接受浮点数的字段中。第 3 行代码导入之前下载并安装好的 MySQLdb 扩展模块,以使我们可以使用其中的方法来连接 MySQL 数据库和数据表。

第 8 行代码使用 sys 模块在命令行中读取文件的路径和名称,并将这个值赋给变量 input_file。

第 10 行代码使用 MySQLdb 模块的 connect() 方法连接 my_suppliers,即在上一节中创建的 MySQL 数据库。与处理 CSV 和 Excel 文件不同(对这两种文件,你是对文件本身进行读取、修改或删除操作),MySQL 建立的数据库就像一台独立计算机(服务器),你可以向数据库请求连接、发送数据和请求数据。在连接时,需要指定一些通用参数,包括 host、port、db、user 和 passwd。

host 是数据库所在的机器的主机名。在本例中,MySQL 服务器保存在你的计算机上,所以 host 是 localhost。当你连接其他数据源时,服务器可能位于不同的机器上,所以你需要修改 localhost,更换成服务器所在的机器的主机名。

port 是 MySQL 服务器的 TCP/IP 连接端口号。我们要使用的端口号是默认的端口号 3306。和 host 参数一样,如果你不在本地主机上工作,而且你的 MySQL 服务器管理员为服务器设置了不同的端口号,那么你必须使用这个端口号去连接 MySQL 服务器。本例中使用了值安装 MySQL 服务器,所以 localhost 是有效的主机名,3306 是有效的端口号。

db 是你想连接的数据库名称。在本例中,我们想连接 my_suppliers 数据库,因为它保存着我们要加载数据的表。如果以后你在本地计算机上创建了另一个数据库,比如 contacts,那么就必须将 db 参数从 my_suppliers 修改为 contacts,来连接这个数据库。

user 是进行数据库连接的用户的用户名。在本例中,我们作为“root”用户进行连接,使用的密码就是在安装 MySQL 服务器时创建的密码。当你安装 MySQL 时(你可以按照附录 A 中的指示步骤完成安装),MySQL 安装程序会要求你为根用户提供密码。在本例中,我们为根用户创建的密码,也就是在代码中提供给 passwd 参数的密码,即 'my_password'。当然,如果你在安装 MySQL 时为根用户创建了不同的密码,那么你应该在脚本代码中使用你自己的密码替换掉 'my_password'。

在创建数据库、表和新用户的步骤中,我创建了一个新用户 clinton,密码为 secret_password。因此,我可以在下列脚本:user='clinton' and passwd='secret_password' 中使用这个连接。如果你想在代码中保留 user='root',那么你应该用在安装 MySQL 服务器时实际设置的密码替换掉 'my_password'。或者,如果你使用 CREATE USER 命令创建了新用户,也可以使用这个新用户的用户名和密码。通过这 5 个参数,你可以创建与 my_suppliers 数据库的本地连接。

第 12 行代码创建了一个光标,我们可以使用它来在 my_suppliers 数据库中对 Suppliers 表执行 SQL 语句,并将修改提交到数据库。

第 14~29 行代码从 CSV 文件中读取要加载到数据表中的数据,并对输入文件中的每行数据执行一条 SQL 语句,将其插入数据表中。第 14 行代码使用 csv 模块创建了 file_reader 对象。第 15 行代码使用 next() 函数从输入文件中读出第一行,也就是标题行,并将其赋给变量 header。第 16 行代码创建了一个 for 循环,在输入文件的所有数据行之间循环。第 17 行代码创建了一个空列表变量 data,对于输入文件中的每一行,用行中的数据去填充 data,这些数据将在第 29 行代码中的 INSERT 语句中使用。第 18 行代码创建了一个 for 循环,在每行数据中的各个列之间循环。第 19 行代码创建了一个 if-else 语句,检验列索引是否小于 4。因为输入文件中有 5 列,而且日期在最后一列,所以日期列的索引值为 4。因此,这行代码判断我们是否在处理日期列前面的列。对于所有日期列前面的列,索引值为 0、1、2 和 3,第 20 行代码将列中的值转换为字符串,如果字符串左侧有美元符号,就剥离掉这个字符,然后将这个值追加到列表变量 data 中。对于最后的日期列,第 23 行代码将其转换为字符串,并使用字符串按照代码中的格式创建一个 datetime 对象,然后将 datetime 对象转换成一个 data 对象(只保留年、月、日),最后将这个值赋给变量 a_date。此后,第 26 行代码将这个 data 对象转换成一个字符串,使用的新格式是要加载到 MySQL 数据库中的日期字符串格式(就是 YYYY-MM-DD),并将格式化好的字符串重新赋给变量 a_date。最后,第 27 行代码将这个字符串追加到 data 中。

第 28 行代码将追加到 data 中的数据打印到命令行窗口或终端窗口上。请注意缩进。这行代码的缩进是在外部 for 循环之下,不是在内部 for 循环之下的,所以它是对于输入文件中的每一行来执行,而不是对于输入文件中的每一行和每一列去执行。这一行有助于调试脚本,但是一旦你确定代码能够正确运行,就可以将这行代码删除或者注释掉,这样在屏幕上就不会打印出过多的输出了。

第 29 行代码是实际将每行数据加载到数据表中的代码。这行代码使用光标对象的 execute() 方法执行一条 INSERT 语句,将一行数据插入到表 Suppliers 中。每个 %s 都是要插入的实际值的占位符。占位符的数量对应着输入文件中列的数量,它们都对应着数据表中列的数量。而且,输入文件中列的顺序也要对应数据表中列的顺序。要替换到 %s 位置的值来自于列表 data,这个列表要放在 execute() 语句中逗号的后面。因为 data 是使用输入文件中的每行数据填充的,而且 INSERT 语句也是对于输入文件中的每行数据执行的,所以这些代码可以高效地从输入文件中读取数据行,并把这些数据行加载到数据表中。再强调一次,要注意缩进。这行代码是在外部 for 循环之下缩进的,所以它对于输入文件中的每一行数据执行一次。最后,第 30 行代码是另一个 commit 语句,将修改提交到数据库。

第 33~39 行代码演示了如何从数据表 Suppliers 中选择所有数据,并将输出打印到命令行窗口或者终端窗口。第 33 和 34 行代码执行一条 SQL 语句,从 Suppliers 表中选择所有数据,并将输出中的所有行读入变量 rows。第 35 行代码创建了一个 for 循环,在 rows 的每一行中循环。第 36 行代码创建了一个空列表变量 row_list_output,用来保存 SQL 查询输出中每一行所有的值。第 37 行代码创建了一个 for 循环,在每行的各个列之间循环。第 38 行代码将每个值都转换成一个字符串,然后追加到 row_list_output 中。最后,当行中所有的值都进入 row_list_output 中后,第 39 行代码将这一行打印到屏幕上。

现在我们已经完成了 Python 脚本,可以使用这个脚本将 supplier_data.csv 中的数据加载到 Suppliers 数据表中了。要完成这个操作,在命令行中输入以下命令,然后按回车键:

python 4db_mysql_load_from_csv.py supplier_data.csv

在 Windows 系统中,你可以看到如图 4-13 所示的输出被打印到命令行窗口中。输出中的第一部分是从 CSV 文件中解析出的数据,第二部分是从数据表中查询出的同样的数据。

图 4-13:输出显示 supplier_data.csv 中的数据就是插入到 MySQL 数据表 Suppliers 中的数据

这个输出展示了 12 个值列表,来自于 CSV 输入文件中除标题行之外的 12 行数据。你可以识别出这 12 个列表,因为每个列表都在方括号([])之间,列表中的每个值以逗号分隔。

在从 CSV 文件中读取的 12 个输入数据列表下面,有一个空行,然后是从数据表中取出的 12 行输出数据,使用的查询语句为 SELECT * FROM Suppliers。每行数据占一行,行中的值以逗号分隔。这个输出证明了数据被成功地加载到了 Suppliers 表中,并被成功读出。

如果要以其他方式确定结果,可以在 MySQL 命令行客户端中输入以下命令,然后按回车键:

SELECT * FROM Suppliers;

按了回车键之后,你会看到一个表格,其中列出了 Suppliers 数据表中所有的列,以及每列中的 12 行数据,如图 4-14 所示。

图 4-14:使用 MySQL 命令行客户端在 Suppliers 表中进行数据查询的结果

现在我们已经有了一个充满数据的数据表,下面就开始学习如何在数据库中进行查询,并使用 Python 将查询结果写入 CSV 文件,而不是打印在屏幕上。

4.2.2 查询一个表并将输出写入CSV文件

数据表中有了数据之后,最常见的下一个步骤就是使用查询从表中取出一组数据,用来进行分析或满足某种商业需求。例如,你可能想知道哪些客户提供了最多的利润,或者哪些费用超过了具体的阈值。

下面创建一个新的 Python 脚本。这个脚本会从 Suppliers 数据表中查询出一组特定记录,然后将输出写入 CSV 输出文件。在这个例子中,我们想找出 Cost 列中的值大于 1000.00 的所有记录,并将这些记录所有列中的值输出。首先,在文本编辑器中输入下列代码,然后将文件保存为 5db_mysql_write_to_file.py:

 1 #!/usr/bin/env python3
 2 import csv
 3 import MySQLdb
 4 import sys
 5 # CSV输出文件的路径和文件名
 6 output_file = sys.argv[1]
 7 # 连接MySQL数据库
 8 con = MySQLdb.connect(host='localhost', port=3306, db='my_suppliers', \
 9 user='root', passwd='my_password')
10 c = con.cursor()
11 # 创建写文件的对象,并写入标题行
12 filewriter = csv.writer(open(output_file, 'w', newline=''), delimiter=',')
13 header = ['Supplier Name','Invoice Number','Part Number','Cost','Purchase Date']
14 filewriter.writerow(header)
15 # 查询Suppliers表,并将结果写入CSV输出文件
16 c.execute("""SELECT *
17          FROM Suppliers
18          WHERE Cost > 700.0;""")
19 rows = c.fetchall()
20 for row in rows:
21     filewriter.writerow(row)

这个示例中的代码几乎就是前一个示例中代码的子集,所以下面将重点介绍其中的新代码。

第 2、3 和 4 行代码分别导入 csv、MySQLdb 和 sys 模块,这样我们就可以使用其中的方法来与 MySQL 数据库进行交互,并将查询结果写入一个 CSV 文件了。

第 6 行代码使用 sys 模块在命令行中读取文件的路径和名称,并将其赋给变量 output_file。

第 8 行代码使用 MySQLdb 的 connect() 方法连接到 my_suppliers,就是我们在本章前面创建的 MySQL 数据库。第 10 行代码创建了一个光标,用来在 my_suppliers 数据库中的 Suppliers 数据表上执行 SQL 语句,并将修改提交到数据库。

第 12 行代码使用 csv 模块的 wirter() 方法创建了 filewriter 对象。

第 13 行代码创建了一个列表变量 header,其中包含 5 个字符串,对应着数据表中的列标题。第 14 行代码使用 filewriter 的 writerow() 方法将这个由逗号分隔的字符串列表写入 CSV 格式的输出文件。数据库查询只输出数据,不输出列标题,所以这些代码可以确保输出文件中的各列有列标题。

第 16~18 行代码是数据库查询,选择 Cost 列中的值大于 700.0 的那些行,并选择这些行中所有的列。因为包含在 3 个双引号之间,所以这个查询可以分布在多行之内。用 3 个双引号封装查询非常有助于将查询写成易读的形式。

第 19~21 行代码与前一个示例中的代码非常相似,不同之处是前一个示例将输出打印到命令行窗口或终端窗口,这个示例的第 21 行代码将输出写入 CSV 格式的输出文件。

我们完成了 Python 脚本,现在可以使用脚本从 Suppliers 数据表中查询出特定数据,并将查询结果写入 CSV 格式的输出文件。要完成这个操作,在命令行中输入以下命令,然后按回车键:

python 5db_mysql_write_to_file.py output_files\5output.csv

在命令行窗口或终端窗口中你不会看到任何输出,但是你可以打开输出文件 5output.csv 查看一下结果。

你可以看到,输出文件中包含一个标题行,其中有 5 个列标题,文件中还有数据表中的 4 行数据,其中 Cost 列中的值大于 700.0。Excel 会将购买日期列中的日期格式化为 MM/DD/ YYYY,Cost 列中的值不包含逗号或美元符号,如果需要的话,对这些值进行格式化也非常容易。

向数据表中加载数据和从数据表中查询数据是对数据表常用的两种操作。另外一种常用操作是更新数据表中已有的行。下一个示例将处理这种情况,介绍如何更新表中已有的行。

4.2.3 更新表中记录

上一个示例介绍了如何使用 CSV 输入文件向一个 MySQL 数据表中批量添加数据,以及如何将 SQL 查询结果写入 CSV 输出文件。但有些时候,我们不需要向表中加载新数据或进行查询,而是需要更新表中已有的行。

幸运的是,我们可以重新使用前面介绍的技术,从 CSV 输入文件中读取数据来更新表中的行。实际上,我们要为 SQL 语句组合一行数据,然后对于 CSV 输入文件中的每一行数据运行一次 SQL 语句,这种技术与前一个示例是完全一样的。只是 SQL 语句有所变化,从 INSERT 语句变为了 UPDATE 语句。

我们已经熟悉了如何使用 CSV 输入文件将数据加载到数据表中,下面学习如何使用 CSV 输入文件更新 MySQL 数据表中已有的记录。要完成这个操作,在文本编辑器中输入下列代码,然后将文件保存为 6db_mysql_update_from_csv.py:

 1 #!/usr/bin/env python3
 2 import csv
 3 import MySQLdb
 4 import sys
 5
 6 # CSV输入文件的路径和文件名
 7 input_file = sys.argv[1]
 8 # 连接MySQL数据库
 9 con = MySQLdb.connect(host='localhost', port=3306, db='my_suppliers', \
10 user='root', passwd='my_password')
11 c = con.cursor()
12
13 # 读取CSV文件并更新特定的行
14 file_reader = csv.reader(open(input_file, 'r', newline=''), delimiter=',')
15 header = next(file_reader, None)
16 for row in file_reader:
17     data = []
18     for column_index in range(len(header)):
19          data.append(str(row[column_index]).strip())
20     print(data)
21     c.execute("""UPDATE Suppliers SET Cost=%s, Purchase_Date=%s \
22     WHERE Supplier_Name=%s;""", data)
23 con.commit()
24 # 查询Suppliers表
25 c.execute("SELECT * FROM Suppliers")
26 rows = c.fetchall()
27 for row in rows:
28     output = []
29     for column_index in range(len(row)):
30          output.append(str(row[column_index]))
31     print(output)

这个示例中的所有代码看上去都很熟悉。第 2~4 行代码导入了 3 个 Python 内置模块,这样我们就可以使用其中的方法来读取 CSV 输入文件、与 MySQL 数据库进行交互和读取命令行输入。第 7 行代码将 CSV 输入文件的路径名赋给变量 input_file。

第 9 行代码与 my_suppliers 数据库建立连接,使用与前一个示例中同样的连接参数。第 11 行代码创建了一个光标对象,用来执行 SQL 查询,并将修改提交到数据库。

第 15~24 行代码与本章第一个示例中的代码几乎是相同的。唯一的明显区别是在第 21 行,UPDATE 语句代替了原来的 INSERT 语句。在 UPDATE 语句中,你必须指定你想更新哪一条记录和哪一个列属性。在这个例子中,我们想为一组特定的 Supplier Names 更新 Cost 值和 Purchase Date 值。像前面的示例一样,UPDATE 语句中需要几个值,就需要几个 %s 占位符表示出查询中的值的位置,CSV 输入文件中数据的顺序也要同查询中属性的顺序一样。在这个例子中,查询中的属性从左到右分别是 Cost、Purchase_Date 和 Supplier_Name;所以,CSV 输入文件中的列从左到右也应该是成本、购买日期和供应商姓名。

最后,第 25~31 行代码和前面示例中这部分的代码基本相同。这些代码从 Suppliers 表中取出所有行,然后在命令行窗口或终端窗口中打印出每一行,并使用一个空格分隔每一列。

现在我们需要一个 CSV 输入文件,其中包含着要用来更新数据表中某些记录的数据:

(1) 打开 Excel。

(2) 添加如图 4-15 中所示的数据。

(3) 将文件保存为 data_for_updating_mysql.csv。

图 4-15:文件 data_for_updating_mysql.csv 中的示例数据,显示在 Excel 工作表中

现在你已经完成了 Python 脚本和 CSV 输入文件,可以使用脚本和输入文件来更新 Suppliers 数据表中的某些行了。要完成这个操作,在命令行中输入以下命令,然后按回车键:

python 6db_mysql_update_from_csv.py data_for_updating_mysql.csv

在 Windows 系统中,你可以看到如图 4-16 所示的输出被打印到命令行窗口上。前两行是 CSV 文件中的数据,其余各行是记录更新之后数据表中的数据。

图 4-16:使用 CSV 文件中的数据更新 MySQL 数据表中的行

这个输出展示了来自于 CSV 输入文件中除标题行之外的两行数据。你可以识别出这两个列表,因为每个列表都包含在方括号([])之间,列表中的每个值以逗号分隔。对于 Supplier X,Cost 值为 600,Purchase Date 值为 2014-01-22。对于 Supplier Y,Cost 值为 200,Purchase Date 值为 2014-02-01。

在这两行下面,输出还展示了执行更新之后从数据表中取出的 12 行数据。每行数据占一行,行中的值由空格分隔。回忆一下,Supplier X 原来的 Cost 值和 Purchase Date 值分别是 500、750 和 2014-01-20。同样,Supplier Y 原来的 Cost 值和 Purchase Date 值分别是 250、125 和 2014-01-30、2013-02-03。从打印在命令行窗口中的输出可以看出,Supplier X 和 Supplier Y 中的这些值已经被修改成了 CSV 输入文件中提供的新值。

为了确认 MySQL 数据表中与 Supplier X 和 Supplier Y 相关的 8 行数据已经被更新,现在回到 MySQL 命令行客户端,输入以下命令,然后按回车键:

SELECT * FROM Suppliers;

按了回车键之后,你可以看到一个表格,其中列出了 Suppliers 数据表中的各列,以及每列中的 12 行数据,如图 4-17 所示。你会看到与 Supplier X 和 Supplier Y 相关的 8 行记录已经被更新为 CSV 输入文件中提供的数据。

图 4-17:Suppliers 表中的记录更新后,使用 MySQL 命令行客户端进行查询的结果

本章介绍了很多基础知识,不仅包括如何使用 sqlite3 创建内存数据库和持久化数据库,以及如何与数据库中的数据表进行交互,还包括创建 MySQL 数据库和数据表、使用 Python 访问 MySQL 数据库和数据表、从 CSV 文件中向 MySQL 数据表中加载数据、使用 CSV 文件中的数据更新 MySQL 数据表中的记录,以及将查询结果写入 CSV 输出文件的方法。如果你一直跟随本章内容练习示例代码,那么你应该完成了 6 个新的 Python 脚本!

练习本章中示例代码的最大收获是,你现在已经很好地掌握了存取数据库中数据的技术,而数据库是商业中最常用的一种数据存储工具。本章重点介绍了 MySQL 数据库系统,但是我们在开头曾提到过,现在有很多其他数据库系统也用于商业中。例如,你可以了解一下 PostgreSQL 数据库系统(http://www.postgresql.org),在 Psycopg(http://initd.org/psycopg)和 PyPI(https://pypi.python.org/pypi/psycopg2)这两个网站,你都可以找到关于 PostgreSQL 的通用 Python 连接适配器的信息。同样,你也可以了解一下 Oracle 数据库系统(https://www.oracle.com/database/index.html),在 SourceForge(http://cx-oracle.sourceforge.net)和 PyPI(https://pypi.python.org/pypi/cx_Oracle)这两个网站,你可以找到关于 Oracle 连接适配器的信息。此外,还有一个常用的 Python SQL 工具箱,名为 SQLAlchemy(http://www.sqlalchemy.org),可以同时支持 Python2 和 Python3,其中包括 SQLite、MySQL、PostgreSQL、Oracle 和若干其他数据库系统的适配器。

到此为止,我们学习了在 CSV 文件、Excel 工作簿和数据库中存取、浏览和处理数据的方法,这是商业中最常用的 3 种数据源。下一步,我们将介绍几个应用程序,看看如何综合运用这些技术解决具体问题。首先,我们讨论如何在一个大的文件集合中找到一组特定的项目。其次,第二个应用程序演示了在输入文件中为任意数目的分类计算统计量的方法。

最后,第三个应用程序演示了如何分析文本文件并为任意数目的分类计算统计量。在学习了这些示例之后,你应该可以掌握如何综合运用在本书中学到的技能来解决具体问题了。

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文