从Python介绍SQL的基础(二)

在前一篇文章中给大家介绍了SQL的CRUD,通过那四个基本操作已经可以从数据库中提取和修改数据了。

之所以叫做关系型数据库是因为表之间通过公共的ID进行关联。所以这篇文章我给大家引入一些其他的表:学生表,老师表。这里的学生和老师都一个名字字段和身份证号码,其中姓名可以重复,而身份证号码则不能。

关联关系

先看下创建老师和学生的SQL语句:

create table teacher (id int, name varchar(24));
insert into teacher values (1001, 'wang');
insert into teacher values (1002, 'john');
insert into teacher values (1003, 'yue');

create table student (id int, name varchar(24));
insert into student values (411, 'leilei');
insert into student values (412, 'hanmeimei');
insert into student values (413, 'jim');
insert into student values (414, 'lucy');

我们先认识下表中的行数据的关系种类:一对一,一对多,多对多。

一对一我们可以这么理解:假设给老师分配停车位,那么一个老师只会有一个。那么我们在数据中建立关系的时候可以将停车位号码作为老师表的一列;假如一个老师有多个停车位,那么我们需要另建一张表专门存放数据。
在这里,我们假设每个课程都是由一个老师教的,同时每个老师可以教几门课程。在python中,需要有一个对象类(包含有课程,并且包含课程的ID);一对多的例子可以看学生和课程的关系:每个课程都有很多学生,学生则学习很多课程,这种关系是肯定需要另一个表来描述的。

这里给出其他的表的SQL:

create table course (number int, name varchar(24), credits int, teacherId int);
insert into course values (101, 'yuwen', 5, 1003);
insert into course values (201, 'shuxue', 5, 1002);
insert into course values (150, 'yingyu', 2, 1001);
insert into course values (301, 'wuli', 5, 1002);
insert into course values (314, 'huaxue', 4, 1001);

create table enrolled (studentId int, courseNumber int);
insert into enrolled values (411, 201);
insert into enrolled values (411, 150);
insert into enrolled values (411, 314);
insert into enrolled values (412, 101);
insert into enrolled values (412, 301);
insert into enrolled values (412, 314);
insert into enrolled values (413, 204);
insert into enrolled values (413, 314);

与python的连接

使用pg模块到Python程序中可以获得与psql相同的对postmaster服务器的访问权限。

给大家演示下pg模块的使用方式。我们在程序中必须做的第一件事是建立到数据库的连接。这是一个例子:

>>> import pg
>>> conn = pg.connect(dbname="school", host="localhost", user="souxianyu")

由于postmaster服务是在本地运行的,所以使用的是-i localhost模式,我们可以像plsql那样是查询数据库:

>>> result = conn.query("select * from kecheng")
>>> print result
number|name       |credits|teacherid
------+-----------+-------+---------
101|yuwen      |      5|   1003
201|shuxue     |      5|   1002
150|yingyu     |      2|   1001
301|wuli       |      5|   1002
314|huaxue     |      4|   1001
(5 rows)

在程序里,我们肯定不会只要这样打印出数据,在这里,result是一个具有属性和方法的对象,这些特性可以让我们用python的值的形式来访问数据。

>>> print result.dictresult()
[{'number': 101, 'name': 'yuwen', 'credits': 5, 'teacherid': 1003},
{'number': 201, 'name': 'shuxue', 'credits': 5, 'teacherid': 1002},
{'number': 150, 'name': 'yingyu', 'credits': 2, 'teacherid': 1001},
{'number': 301, 'name': 'wuli', 'credits': 3, 'teacherid': 1002},
{'number': 314, 'name': 'huaxue','credits': 3, 'teacherid': 1001}]

也可以使用join来连接多张表:

>>> cmd = """select kecheng.name,teacher.name from kecheng,teacher
...           where teacher.id=kecheng.teacherId order by kecheng.name"""
>>> result = conn.query(cmd)
>>> print result.dictresult()
[{'name': 'yuwen'}, {'name': 'teacher A'},
{'name': 'shuxue'}, {'name': 'teacher B'},
{'name': 'yingyu'}, {'name': 'teacher C'}]

实际演示程序

最后同一个小程序给大家演示下实际的使用,这个程序按照字母顺序排列出老师,并且同样按照字母顺序排列他们教的课程。

#!/usr/bin/env python
import pg
db = pg.connect(dbname="school", host="localhost", user="souxianyu")

def main () :
result = db.query("select * from teacher order by name")
trows = result.dictresult()
for trow in trows :
tId = trow['id']
print "%s" % trow['name']
query ="select * from kecheng where teacherId=%d order by name"
result = db.query(query % tId)
crows = result.dictresult()
for crow in crows :
print "  %s" % crow['name']  # Name of kecheng

上面的程序中,我们首先从教师表中选择行。然后我们为每位老师选择所教的课程。输出如下所示:

teacher A
teacher B
teacher C
shuxue
yingyu
yuwen

我们再来另一种实现方式:

#!/usr/bin/env python
import pg
cmd = """
select teacher.name as tname, kecheng.name as kname
from teacher, kecheng
where teacher.id = kecheng.teacherId
order by teacher.name, kecheng.name"""

db = pg.connect(dbname="school", host="localhost", user="souxianyu")

def main () :
kcTeacher = None
result = db.query(cmd)
rows = result.dictresult()
for row in rows :
if row['tname'] != kcTeacher :
kcTeacher = row['tname']
print "%s" % kcTeacher
print "  %s" % row['cname']  # Name of kecheng

if __name__ == "__main__" : main()

可能大家会问了,为什么要出两种方法,有什么区别呢。
假设这学校有1000个老师,第一个方法需要1001个查询,而第二种则只要1此,明显第二种会更快。但是假如查询语句变得很复杂,由很多张表关联查询的话,对服务器造成的压力还是很大的,这时候第一种则会更妥当一点。
因此并没有哪种比另一种一定好的说法,这需要大家在实际的开发过程中结合环境和业务选择不同的方法。

好了,这次关于SQL的讲解就结束了,第一次分次写文章,希望大家还能跟得上我的思路!

版权所属,如需转载,请注明出处:搜闲鱼

2,013 次浏览

发表评论

邮箱地址不会被公开。 必填项已用*标注