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()
SQL 原生查詢:
Left Join
select * from table1 Left Join table2 where table1.ID = table2.ID
左連接后的檢索結果是顯示table1的所有數據和table2中滿足where 條件的數據。
簡言之 Right Join影響到的是右邊的表,左邊的表全部展示,而右邊的表只能展示條件限制之內的。
右連接,右連接和左連接相反。1.0本不支持
SQL 原生:
Right Join
select * from table1 Right Join table2 where table1.ID = table2.ID
檢索結果是table2的所有數據和table1中滿足where 條件的數據。
簡言之 Right Join影響到的是左邊的表,右邊的表里的數據全部展示,而左邊表里的數據只能展示條件限制之內的。
全連接,則是將兩個表的需要的字段的數據全排列。全連接比較特殊,使用一個參數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()