吃貨眼中的sqlalchemy外來鍵和連表查詢
前言
使用資料庫一個高效的操作是連表查詢,一條查詢語句能夠查詢到多個表的資料。在sqlalchem架構下的資料庫連表查詢更是十分方便。那麼如何連表查詢?以及資料庫外來鍵對連表查詢有沒有幫助呢?本篇文章就這兩個問題簡單解釋。
建表
俗話說巧婦難為無米之炊,連表查詢肯定要有表,有資料庫啊。那有沒有資料庫是你見了垂涎三尺的呢?中國文化博大精深,飲食文化更是璀璨的明珠。我們就以中國菜系為話題,講一講好吃的,順便再說一說外來鍵和連表查詢。
魯菜 山東菜系,而且在明清兩代,宮廷御膳是以魯菜為主,魯菜味道濃厚,喜歡蔥蒜,以海鮮、湯菜和內臟為主。因為魯菜對其他菜系的影響頗大,所以魯菜為八大菜系之首。代表:糖醋鯉魚
川菜 四川菜系,以成都和重慶兩地菜系為主,特點是酸、甜、麻、辣、香,川菜中有五大名菜:回鍋肉、水煮肉片、麻婆豆腐、宮保雞丁、魚香肉絲。川菜太好吃了,名菜超多。
蘇菜 江蘇地方風味菜,由揚州、南京、蘇州三地的地方菜發展而成,是宮廷第二大菜系,今天國宴仍以蘇菜為主。其中揚州菜亦稱淮揚菜,因受本地自然資源影響,菜色四季有別,講究配色以及烹飪技巧。代表作:鹽水鴨,松鼠桂魚
粵菜。就是廣東菜系,在國外的中國菜館是以粵菜為主的。粵菜分為潮汕風味、廣府風味以及客家風味,又以廣府風味為代表。廣東地域物產豐富且新鮮,而且講究季節性。選材要在食物的最佳的時節,做法追求食材的原汁原味,不像川菜那樣破壞了食材原來的鮮味。代表作:白斬雞
那麼就以上面提到的資訊來建兩張表。
food表:
菜系 | 地區 |
魯菜 | 山東 |
川菜 | 成都 |
蘇菜 | 南京 |
粵菜 | 珠三角 |
famous表:
菜系 | 代表 |
魯菜 | 糖醋鯉魚 |
川菜 | 魚香肉絲、宮保雞丁、水煮肉片 |
蘇菜 | 松鼠桂魚、鹽水鴨 |
粵菜 | 白斬雞 |
不帶外來鍵的兩張表:
model.py
#coding:utf-8 from sqlalchemy import create_engine from sqlalchemy.ext.declarative import declarative_base from sqlalchemy import Column,Integer,String,DATE,ForeignKey,CHAR #匯入外來鍵 from sqlalchemy.orm import relationship #建立關係 engine = create_engine("mysql+mysqldb://root:12345678@localhost:3306/test?charset=utf8", encoding="utf-8") Base = declarative_base() #生成orm基類 class Food(Base): __tablename__ = "food" name = Column(CHAR(20),primary_key = True) location = Column(CHAR(20)) def __repr__(self): return "name:{0} location:{1}".format(self.name,self.location) class Famous(Base): __tablename__ = 'famous' id = Column(Integer,primary_key = True) food_name = Column(CHAR(20)) famous_dish = Column(CHAR(20)) def __repr__(self): return "id:{0} food_name:{1} famous_dish:{2}".format(self.id,self.food_name,self.famous_dish) Base.metadata.create_all(engine) #建立表
寫入資料
寫入資料:
#coding:utf-8 from sqlalchemy.orm import sessionmaker from sqlalchemy.ext.declarative import declarative_base from sqlalchemy import create_engine,Column from model import Food,Famous
#中文在命令列中顯示為16進位制編碼,所以用拼音代替,懂這個意思就行。 food = { u"lu":u"shandong", u"chuan":u"chengdu", u"su":u"nanjing", u"yue":u"zhusanjiao" } famous = [ {u'lu':u'tangculiyu'}, {u'chuan':u'yuxiangrousi'}, {u'chuan':u'gongbaojiding'}, {u'chuan':u'shuizhuroupian'}, {u'su':u'songshuguiyu'}, {u'su':u'yanshuiya'}, {u'yue':u'baizhanji'} ] engine = create_engine('mysql+mysqldb://root:12345678@localhost:3306/test?charset=utf8') DBSession = sessionmaker(bind=engine) session = DBSession() for key in food: new_food = Food(name=key,location=food[key]) session.add(new_food) session.commit() for dish in famous: new_famous = Famous(food_name=dish.keys()[0],famous_dish=dish.values()[0]) session.add(new_famous) session.commit() session.close()
這裡有一點值得注意一下,famous的外來鍵是food_name欄位,指向的是food表中主鍵name欄位。並且這裡的對應關係是1對多的。在famous表中的food_name欄位重複出現了,但值只有4種。這裡就是外來鍵的特性之一:
外來鍵對應主表的主鍵,外來鍵值可以是空,可以多個對1個,但一定要在主表中主鍵的值裡。
有關外來鍵的具體內容可以參考前面一篇 sqlalchemy外來鍵和relationship查詢
查詢
select.py
#coding:utf-8 from sqlalchemy.orm import sessionmaker from sqlalchemy import create_engine from model import * #修改使用者名稱、密碼和資料庫的名稱為自己的 engine = create_engine("mysql+mysqldb://root:12345678@localhost:3306/test",) Session_class = sessionmaker(bind=engine) session = Session_class() query = session.query(Food).join(Famous).all() for x in query: print x
在沒有外來鍵關聯的情況下對查詢是有一定的影響的,沒有外來鍵關聯的情況下,直接join連表,而不指明連表的欄位就會報錯,因為sqlalchemy連表查詢沒有外來鍵自動關聯兩張表。
query = session.query(Food).join(Famous).all()
這個時候就需要在使用join連表時指明兩張表連線的欄位。
query = session.query(Food,Famous).join(Famous,Famous.food_name==Food.name).all()
帶外來鍵的表
#coding:utf-8 from sqlalchemy import create_engine from sqlalchemy.ext.declarative import declarative_base from sqlalchemy import Column,Integer,String,DATE,ForeignKey,CHAR #匯入外來鍵 from sqlalchemy.orm import relationship #建立關係 engine = create_engine("mysql+mysqldb://root:12345678@localhost:3306/test?charset=utf8", encoding="utf-8") Base = declarative_base() #生成orm基類 class Food(Base): __tablename__ = "food" name = Column(CHAR(20),primary_key = True) location = Column(CHAR(20)) def __repr__(self): return "name:{0} location:{1}".format(self.name,self.location) class Famous(Base): __tablename__ = 'famous' id = Column(Integer,primary_key = True) food_name = Column(CHAR(20),ForeignKey('food.name')) food = relationship("Food",backref="dish_belong_food") famous_dish = Column(CHAR(20)) def __repr__(self): return "id:{0} food_name:{1} famous_dish:{2}".format(self.id,self.food_name,self.famous_dish) Base.metadata.create_all(engine) #建立表
加了外來鍵的famous表,從其建表的sql來看有一條外來鍵記錄,連線到food表中的name欄位。
有外來鍵關聯的表,能夠直接join表,sqlalchemy會自動用外來鍵關聯這兩張表,這就是sqlalchemy對查詢做出的優化。
query = session.query(Food,Famous).join(Famous).all()
連表查詢
資料庫連表有很多中操作,有全連線,左連線,右連線。在這些連線方式中,最基礎的是全連線,看一下全連線的威力。
query = session.query(Food,Famous).all()
直接查詢兩張表,這時查詢結果是返回被連線的兩個表的笛卡爾積。將兩張表看做是兩個列表,全連線的方式類似如下的列表乘積。
在前面使用的join連線則是一種內連線。將兩張表裡相同的部分連線在一起,內連線的方式如下:
query = session.query(Food,Famous).join(Famous,Famous.food_name==Food.name).all()
使用join的方式可以將多張表連在一起,不僅限於2張表,如果這裡有還有一張介紹每一種美食的做法的一張表叫做Cook的話,將三種表連起來的寫法:
query = session.query(Food,Famous,Cook).join(Famous,Famous.food_name==Food.name).join(Cook,Cook.famous_name==Famous.famous).all()
只要表與表之間有關聯,那麼就能用join的方式將表連線在一起,前提是一定要有欄位是有關聯的,如果連線兩張毫無干系的表,那查詢結果肯定是空。
在實際的使用過程中,將想要查詢的表關聯起來是第一步,還有一步也很重要,那就是過濾,篩選出我們需要的欄位。而篩選在sqlalchemy中使用的是filter這個關鍵字。例如,想要篩選出所有蘇菜裡的好吃的,可以這麼寫:
query = session.query(Food,Famous).join(Famous,Famous.food_name==Food.name).filter(Food.name=='su').all()
filter的作用就是從得到連表所有的資料裡過濾出我們感興趣的資料。filte之前,我們得到的資料是這樣的:
而使用了filter之後,從上面的結果中將food表中name欄位為'su'的資料過濾出來,便是如下的資料:
同時還可以多級過濾,可以在前面的基礎上再次過濾。比如說,我就愛吃鴨子,我在南京的美食找一找有沒有和鴨子有關的好吃的,寫法如下:
query = session.query(Food,Famous).join(Famous,Famous.food_name==Food.name).filter(Food.name=='su').filter(Famous.famous_dish.like('%ya%')).all()
結果如下,真的找到一條記錄,鹽水鴨,這是南京人民的最愛啊
總結
所以總結一下在sqlalchemy中如何得心應手,隨心所欲的過濾出自己想要的資料:
1.找到你想要查詢的資料的表
2.看看你手裡有什麼資料
3.確定手裡的資料和你要查詢的資料之間有直接關係還是有間接關係
4.將有關聯的表連線起來(join ,連線相關的表)
5.從得到的資料中過濾出裡感興趣的資料(filter 過濾出你需要的資料)
通用公式
query 負責你要查詢的結果的欄位資訊
join 負責你的連表操作,可以有多個join
filetr 負責過濾你感興趣的資料,或者符合條件的資料才能被query展示
看到這裡可能有好奇寶寶會問,不是還有一個all嗎?這是什麼意思呢?這個就是sqlalchemy的關鍵字了,具體參考前面的sqlalchemy關鍵字使用篇