1. 程式人生 > >吃貨眼中的sqlalchemy外來鍵和連表查詢

吃貨眼中的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關鍵字使用篇