SQLAlchemy是Python编程语言下的一款ORM框架,该框架建立在数据库API之上,使用关系对象映射进行数据库操作。将对象转换成SQL,然后使用数据API执行SQL并获取执行结果。在写项目的过程中,常常要使用SQLAlchemy操作数据库,同事前期教我很多东西,感谢之余写一篇文章记录使用过的技术,做到心里有数,手上有活。
在开发过程中涉及到的内容:
- 联表查询(外键加持)
- 联表查询(无外键)
- and 多条件与查询
- or 多条件或查询
- in 包含查询
- offset&limit 切片查询
相关查询操作还有:
- ~ 取反操作
- is_ 空值判断
- between
- like 模糊查询
最后补充:
- 查询数据类型判断
- 多表连接方式(全连接,外连接,内连接)
准备工作
1.sqlalchmey开发环境的搭建
pip install sqlalchemy
2.安装mysql数据库
sudo apt-get install mysql-server
3.创建数据库mydb
create database mydb default charset utf8
创建数据库时一定要加上数据的编码方式,否则无法存入中文。
4.下载mysql的python驱动
apt install MySQL-python
创建模型和数据
创建表结构
定义四张表:Student,Family,House,Car。关系如下:
代码创建过程:
1 from sqlalchemy import Column,String,create_engine,MetaData,ForeignKey,Integer 2 from sqlalchemy.orm import sessionmaker 3 from sqlalchemy.ext.declarative import declarative_base 4 from sqlalchemy.orm import sessionmaker 5 6 Base = declarative_base() 7 meta = MetaData() 8 9 10 #定义User对象 11 class Student(Base): 12 __tablename__ = 'student' 13 id = Column(String(20),primary_key=True) 14 name = Column(String(20)) 15 16 class Family(Base): 17 __tablename__ = 'family' 18 id = Column(String(20),primary_key=True) 19 member = Column(Integer) 20 student_id = Column(String(20),ForeignKey('student.id')) 21 22 class House(Base): 23 __tablename__ = 'house' 24 id = Column(String(20),primary_key=True) 25 location = Column(String(100)) 26 family_id = Column(String(20),ForeignKey('family.id')) 27 28 class Car(Base): 29 __tablename__ = 'car' 30 id = Column(String(20),primary_key=True) 31 name = Column(String(100)) 32 family_id = Column(String(20)) 33 34 35 def create_fun(): 36 37 #初始数据库连接 38 engine = create_engine('mysql+mysqldb://root:123@127.0.0.1:3306/mydb?charset=utf8',echo=True) 39 #创建DBsession 40 DBSession = sessionmaker(bind=engine) 41 42 #创建session会话,数据库操作的基石。 43 session = DBSession() 44 45 #在数据库中创建表user 46 Student.metadata.create_all(bind=engine) 47 Family.metadata.create_all(bind=engine) 48 House.metadata.create_all(bind=engine) 49 50 #插入数据 51 stu_one = Student(id='1',name= '悟空') 52 stu_two = Student(id='2',name='贝吉塔') 53 stu_three = Student(id='3',name='比克') 54 stu_four = Student(id='4',name='') 55 56 #提交数据到session 57 58 session.add(stu_one) 59 session.add(stu_two) 60 session.add(stu_three) 61 62 session.add(stu_four) 63 session.commit() 64 65 family_one = Family(id='1',member=7,student_id='1') 66 family_two = Family(id='2',member=5,student_id='2') 67 family_three = Family(id='3',member=8,student_id='3') 68 69 session.add(family_one) 70 session.add(family_two) 71 session.add(family_three) 72 session.commit() 73 74 house_one = House(id='1',location='地球',family_id='1') 75 house_two = House(id='2',location='贝吉塔星',family_id='2') 76 house_three = House(id='3',location='美克星人',family_id='3') 77 house_four = House(id='4',location='地球',family_id='3') 78 79 session.add(house_one) 80 session.add(house_two) 81 session.add(house_three) 82 session.add(house_four) 83 session.commit() 84 85 car_one = Car(id='1',name='筋斗云',family_id='1') 86 car_two = Car(id='2',name='奔驰',family_id='2') 87 car_three = Car(id='3',name='宝马',family_id='3') 88 89 session.add(car_one) 90 session.add(car_two) 91 session.add(car_three) 92 #提交到数据库 93 session.commit() 94 95 session.close() 96 97 if __name__ == '__main__': 98 create_fun()
创建了四张表,写入了多条数据。
查询
首先来一波基础查询,了解各个表的数据。
student表
Family表
House表
Car表
两张表连表查询
查询Student表,限制条件是Family表中的member字段。Family表外键关联到Student表,查询Family中member 大于6的Student表数据。即家庭成员大于6人的学生表。
result = session.query(Student).join(Family).filter(Family.member>6)
两张表连表查询使用了join关键字。 将Family表添加到Student表中,通过外键关联到一起。通过打印的查询sql语句可以看出,sqlalchemy的join使用的是'INNER JOIN',即内连接方式。可以说,内连接方式是sqlalchemy的默认连接方式。
三张表连表查询
查询Student表,限制的条件是House表中的location字段。
result_two = session.query(Student).join(Family).join(House).filter(House.location=='美克星人')
查询语句使用了两次join,student表连接了family和house。底层的sql查询语句同样使用了INNER JOIN方式。目前三张表的连接方式如下所示:
无外键加持的连表查询
没有外检关联时,使用join关键字连表查询。
result_three = session.query(Student).join(Family).join(Car).filter(Car.name=='宝马')
从报错信息来看,找不到外键关联。这里Car表没有和其他表做外键关联,所有这里找不到关联关系。
无外键的join连表查询
如果建表时使用了外键关联,那么可以直接使用join关键字连接数据库查询。如果没有外键关联,也可以连表查询,只需要指明外键关系即可。
result = session.query(Student).join(Family).join(Car,Car.family_id==Family.id).filter(Car.name=='宝马')
还是上面的查询语句,指明关联字段 Car.family_id==Family.id 。
这样就可以完成连表查询。
or操作
or操作常用于满足多个条件中的一个条件情况下,例如下面一调语句是指满足location是地球,或者member=7的条件。只要这两种条件其中一种满足即可。
result_four = session.query(Student.name,Family.member,House.location).join(Family).join(House).filter(or_(House.location=='地球',Family.member==7))
and操作
和or相反的,and是所有的条件必须要满足。上面的例子是指同时满足location是地球,member等于7的条件。所有or有两个结果,and就只有一个结果。
result = session.query(Student.name,Family.member,House.location).join(Family).join(House).filter(and_(House.location=='地球',Family.member==7))
in操作
in操作是一个很方便的操作。如果没有in的话,可以用or同样来完成,但是效率会低,代码也不够简洁。如in_((4,5,6))等价于or_(Family.member == 4,Family.member==5,Family.member==6)。数量多的情况下in操作是效率很高的操作。
result_six = session.query(Student.name,Family.member).join(Family).filter(Family.member.in_((4,5,6)))
offset & limit切片操作
之所以将offset和limit放在一起来将,是因为这两位常常是一起出现的。对的,你猜的不错,就是前台分页是使用。抛开后台分页工具,如果熟练使用offset和limit,自己完全可以写一个后台分页器。
#offset。 result_seven = session.query(Student).offset(2).all()#从指定的下表开始取数据 #limit result_ten = session.query(Student).limit(2).all()#指定要取的数据的个数
~ 取反操作
result = session.query(Student.name,Family.member).join(Family).filter(~Family.member.in_((4,5,6)
between
result = session.query(Student).filter(Student.id.between(1,2))
like 统配
like的参数有两种写法,分别是带%s和不带。使用%来做通配符,带%表示模糊查询;不带表示精确查询
模糊查询
result = session.query(Student).filter(Student.name.like('悟%'))
精确查询
result = session.query(Student).filter(Student.name.like('悟'))
is空值判断
result = session.query(Student).filter(Student.name.is_(None))
查询结果类型分析
result = session.query(Student)
query查询出来的是对象。对象可以继续filter过滤,也可以all取出所有。
result = session.query(Student).all()
all()方法查询出来的是列表。一定要主意在列表是空值的情况下使用取值或者别的操作会造成报错。
result = session.query(Student).filter(id==1)
filter查询出来的是对象。对象支持链式操作,一个filter后面可以继续增加多个filter操作。
连接方式
SQLAlchemy 内,外,左,右,全连接
在连表查询时,从打印出来的sql语句可以看出join是使用了内连接的方式来完成的。内连接的连接方式如下,查询两张表中相同的部分。
外链接,也叫左连接。以左边的表为主表,右边的表为副表,将主表中需要的字段全部列出,然后将副表中的数据按照查询条件与其对应起来。使用关键字outerjoin
Family.query.outerjoin(House).all()
右连接,右连接和左连接相反。1.0本不支持
全连接,则是将两个表的需要的字段的数据全排列。全连接比较特殊,使用一个参数full=True 来完成全连接。1.0版本不支持
Student.query(Student.id,Family.member).join(Family,Family.id ==Student.id, full=True)
查询的全部代码
#coding:utf-8 from sqlalchemy.orm import sessionmaker from sqlalchemy import create_engine,and_,or_ from sqlalchemy_improve_two import Student,Family,House,Car # print "初始化数据库引擎" engine = create_engine("mysql+mysqldb://root:123@localhost:3306/mydb?charset=utf8") # print "创建session对象" DBSession = sessionmaker(bind=engine) session = DBSession() def select_join(): # result = session.query(Student) # result = session.query(Family) # result = session.query(House) # result = session.query(Car) # print '两张表联表查询' # print 'Student表joinFamily表,通过查找Family表中member字段大于6的Student表中数据' # result = session.query(Student).join(Family).filter(Family.member>6) #三张表连表查询 # result = session.query(Student).join(Family).join(House).filter(House.location=='美克星人') #没有外键关系的join查询。car与其他表没有外键关系 # result_three = session.query(Student).join(Family).join(Car).filter(Car.name=='宝马') #在没有外键关联的情况下使用join连接两张表 # result = session.query(Student).join(Family).join(Car,Car.family_id==Family.id).filter(Car.name=='宝马') #or 操作 # result = session.query(Student.name,Family.member,House.location).join(Family).join(House).filter(or_(House.location=='地球',Family.member==7)) #in操作 # result = session.query(Student.name,Family.member).join(Family).filter(Family.member.in_((4,5,6))) #offset # result = session.query(Student).offset(2) #limit # result = session.query(Student).limit(2) #~取反操作 # result = session.query(Student.name,Family.member).join(Family).filter(~Family.member.in_((4,5,6))) #between # result = session.query(Student).filter(Student.id.between(1,2)) #like # result = session.query(Student).filter(Student.name.like('悟%')) # result = session.query(Student).filter(Student.name.like('悟')) #空值判断 # result = session.query(Student).filter(Student.name.is_(None)) # result = session.query(Student) # result = session.query(Student).all() result = session.query(Student).filter(id==1) # print 'sql语句:' # print result print 'result的数据类型:' print type(result) print '查询结果:' for x in result: print x.id,x.name if __name__ == "__main__": select_join() # print '关闭数据库连接' session.close()