2011-12-25 149 views
1

在此先感謝您的幫助。SQLAlchemy:單向關係,相關子查詢

我有兩個實體,人類和黑猩猩。每個都有一組度量標準,它們可以包含MetricBlock的子類,例如CompleteBloodCount(字段WHITE_CELLS,RED_CELLS,PLATELETS)。

所以我的對象模型看起來像(原諒ASCII藝術):

--------- metrics ---------------  ---------------------- 
| Human | ----------> | MetricBlock | <|-- | CompleteBloodCount | 
---------    ---------------  ---------------------- 
         ^
--------- metrics | 
| Chimp | -------------- 
--------- 

這是通過下面的表格來實現:

Chimp (id, …) 
Human (id, …) 

MetricBlock (id, dtype) 
CompleteBloodCount (id, white_cells, red_cells, platelets) 
CholesterolCount (id, hdl, ldl) 

ChimpToMetricBlock(chimp_id, metric_block_id) 
HumanToMetricBlock(human_id, metric_block_id) 

所以人都知道它的度量塊,但度量塊不知道它的人類或黑猩猩。

我想在SQLAlchemy中編寫一個查詢來查找特定人類的所有CompleteBloodCounts。在SQL我可以寫這樣的東西:

SELECT cbc.id 
FROM complete_blood_count cbc 
WHERE EXISTS (
    SELECT 1 
    FROM human h 
     INNER JOIN human_to_metric_block h_to_m on h.id = h_to_m.human_id 
    WHERE 
     h_to_m.metric_block_id = cbc.id 
) 

我很努力,雖然寫在SQLAlchemy。我認爲correlate(),any()或別名連接可能會有所幫助,但MetricBlock不知道其Human或Chimp的事實對我來說是一個絆腳石。

有沒有人有關於如何編寫此查詢的任何建議?或者,是否有其他策略以SQLAlchemy更好的方式定義模型?

感謝您的協助。

Python 2.6 
SQLAlchemy 0.7.4 
Oracle 11g 

編輯:

HumanToMetricBlock定義爲:

humanToMetricBlock = Table(
    "human_to_metric_block", 
    metadata, 
    Column("human_id", Integer, ForeignKey("human.id"), 
    Column("metric_block_id", Integer, ForeginKey("metric_block.id") 
) 

per the manual

回答

3

不論靈長類型是什麼類型,每個靈長類動物都應該有一個唯一的ID。我不確定爲什麼每組屬性(MB,CBC,CC)都是獨立的表格,但我認爲它們具有多個維度(靈長類),例如時間,否則我只會有一個巨大的表格。

因此,我會按以下方式構建此問題: 創建父對象靈長類動物並從中派生人類和黑猩猩。本示例使用單表繼承,但您可能希望使用基於屬性的連接表繼承。

class Primate(Base): 
    __tablename__ = 'primate' 
    id = Column(Integer, primary_key=True) 
    genus = Column(String) 
    ...attributes all primates have... 
    __mapper_args__ = {'polymorphic_on': genus, 'polymorphic_identity': 'primate'} 

class Chimp(Primate): 
    __mapper_args__ = {'polymorphic_identity': 'chimp'} 
    ...attributes... 

class Human(Primate): 
    __mapper_args__ = {'polymorphic_identity': 'human'} 
    ...attributes... 

class MetricBlock(Base): 
    id = ... 

然後創建一個單一的許多一對多表(可以使用關聯代理代替):

class PrimateToMetricBlock(Base): 
    id = Column(Integer, primary_key=True) # primary key is needed! 
    primate_id = Column(Integer, ForeignKey('primate.id')) 
    primate = relationship('Primate') # If you care for relationships. 
    metricblock_id = Column(Integer, ForeignKey('metric_block.id') 
    metricblock = relationship('MetricBlock') 

然後我會結構中的查詢像這樣(注意,上子句沒有必要的,因爲SQLAlchemy的能夠自動推斷的關係,因爲沒有歧義):

query = DBSession.query(CompleteBloodCount).\ 
    join(PrimateToMetricBlock, PrimateToMetricBlock.metricblock_id == MetricBlock.id) 

如果您想通過靈長類動物類型過濾,加入靈長類表和過濾:

query = query.join(Primate, Primate.id == PrimateToMetricBlock.primate_id).\ 
    filter(Primate.genus == 'human') 

否則,如果你知道靈長類動物(primate_id)的ID,無需額外連接是必要的:

query = query.filter(PrimateToMetricBlock.primate_id == primate_id) 

如果你只檢索一個對象,結束與查詢:

return query.first() 

否則:

return query.all() 

像這樣形成你的模型應該可以消除任何混淆,並且使一切變得簡單。如果我錯過了什麼,請告訴我。

+0

嗨喬納森,謝謝你的快速回復。我使用模型定義編輯了多對多連接表的帖子,我想知道是否可以根據映射來闡明您的帖子?我不知道我實際上可以參考這張表。再次感謝。 – j128 2011-12-25 02:26:51

+0

問一個不同的方式,有沒有辦法只使用human.metrics?我有一個人或一個黑猩猩,我想CBC的,我想我需要在Python中查找查找連接表。我很抱歉沒有在帖子中提出更好的建議。我的問題和你的功能名稱僅限於人類。 – j128 2011-12-25 02:32:53

+0

啊,我想我找到了一個更好的辦法來做這個問題。讓我編輯答案。 – 2011-12-25 06:16:50