SQLAlchemy中关联表的联接关联表

2024-06-28 15:16:35 发布

您现在位置:Python中文网/ 问答频道 /正文

我有一个表dna_extraction_protocols,其中包含有关DNA提取协议的数据。许多键被存储在incubations表上的Incubation对象占用。孵化有一个duration_unit键,它包含一个MeasurementUnit对象,该对象包含在measurement_units表中。你知道吗

这些表的创建方式如下:

class DNAExtractionProtocol(Protocol):
    __tablename__ = 'dna_extraction_protocols'
    __mapper_args__ = {'polymorphic_identity': 'dna_extraction'}
    id = Column(Integer, ForeignKey('protocols.id'), primary_key=True)
    sample_mass = Column(Float)
    mass_unit_id = Column(String, ForeignKey('measurement_units.id'))
    mass_unit = relationship("MeasurementUnit", foreign_keys=[mass_unit_id])
    digestion_buffer_id = Column(String, ForeignKey("solutions.id"))
    digestion_buffer = relationship("Solution", foreign_keys=[digestion_buffer_id])
    digestion_buffer_volume = Column(Float)
    digestion_id = Column(Integer, ForeignKey("incubations.id"))
    digestion = relationship("Incubation", foreign_keys=[digestion_id])
    lysis_buffer_id = Column(String, ForeignKey("solutions.id"))
    lysis_buffer = relationship("Solution", foreign_keys=[lysis_buffer_id])
    lysis_buffer_volume = Column(Float)
    lysis_id = Column(Integer, ForeignKey("incubations.id"))
    lysis = relationship("Incubation", foreign_keys=[lysis_id])
    proteinase_id = Column(String, ForeignKey("solutions.id"))
    proteinase = relationship("Solution", foreign_keys=[proteinase_id])
    proteinase_volume = Column(Float)
    inactivation_id = Column(Integer, ForeignKey("incubations.id"))
    inactivation = relationship("Incubation", foreign_keys=[inactivation_id])
    cooling_id = Column(Integer, ForeignKey("incubations.id"))
    cooling = relationship("Incubation", foreign_keys=[cooling_id])
    centrifugation_id = Column(Integer, ForeignKey("incubations.id"))
    centrifugation = relationship("Incubation", foreign_keys=[centrifugation_id])

    volume_unit_id = Column(String, ForeignKey('measurement_units.id'))
    volume_unit = relationship("MeasurementUnit", foreign_keys=[volume_unit_id])

class Incubation(Base):
    __tablename__ = "incubations"
    id = Column(Integer, primary_key=True)
    speed = Column(Float)
    duration = Column(Float)
    temperature = Column(Float)
    movement = Column(String) # "centrifuge" or "shake"

    #speed - usually in RPM - will refer to either centrifugation or shaking (See above)
    speed_unit_id = Column(String, ForeignKey('measurement_units.id'))
    speed_unit = relationship("MeasurementUnit", foreign_keys=[speed_unit_id])
    duration_unit_id = Column(String, ForeignKey('measurement_units.id'))
    duration_unit = relationship("MeasurementUnit", foreign_keys=[duration_unit_id])
    temperature_unit_id = Column(String, ForeignKey('measurement_units.id'))
    temperature_unit = relationship("MeasurementUnit", foreign_keys=[temperature_unit_id]

class MeasurementUnit(Base):
    __tablename__ = "measurement_units"
    id = Column(Integer, primary_key=True)
    code = Column(String, unique=True)
    long_name = Column(String)
    siunitx = Column(String)

现在,我想提取一个Pandas数据帧,在这里我可以获得DNAPurificationProtocol对象、链接的Incubation对象和链接的MeasurementUnit对象的所有属性。你知道吗

我试过很多方法,这一种似乎对第一段感情很有效:

sql_query = session.query(DNAExtractionProtocol, MeasurementUnit, Incubation) \
    .join(MeasurementUnit, MeasurementUnit.id == DNAExtractionProtocol.volume_unit_id) \
    .join(Incubation, Incubation.id == DNAExtractionProtocol.lysis_id) \
    .filter(tables[table].code == code)

但在我看来,这是一种逻辑上的延伸:

sql_query = session.query(DNAExtractionProtocol, MeasurementUnit, Incubation) \
    .join(MeasurementUnit, MeasurementUnit.id == DNAExtractionProtocol.volume_unit_id) \
    .join(Incubation, Incubation.id == DNAExtractionProtocol.lysis_id) \
    .join(MeasurementUnit, MeasurementUnit.id == Incubation.temperature_unit_id) \
    .filter(tables[table].code == code)

失败原因:

sqlalchemy.exc.OperationalError: (sqlite3.OperationalError) ambiguous column name: measurement_units.id [SQL: u'SELECT protocols.type, dna_extraction_protocols.id, protocols.id, protocols.code, protocols.name, dna_extraction_protocols.sample_mass, dna_extraction_protocols.mass_unit_id, dna_extraction_protocols.digestion_buffer_id, dna_extraction_protocols.digestion_buffer_volume, dna_extraction_protocols.digestion_id, dna_extraction_protocols.lysis_buffer_id, dna_extraction_protocols.lysis_buffer_volume, dna_extraction_protocols.lysis_id, dna_extraction_protocols.proteinase_id, dna_extraction_protocols.proteinase_volume, dna_extraction_protocols.inactivation_id, dna_extraction_protocols.cooling_id, dna_extraction_protocols.centrifugation_id, dna_extraction_protocols.volume_unit_id, measurement_units.id, measurement_units.code, measurement_units.long_name, measurement_units.siunitx, incubations.id, incubations.speed, incubations.duration, incubations.temperature, incubations.movement, incubations.speed_unit_id, incubations.duration_unit_id, incubations.temperature_unit_id \nFROM protocols JOIN dna_extraction_protocols ON protocols.id = dna_extraction_protocols.id JOIN measurement_units ON measurement_units.id = dna_extraction_protocols.volume_unit_id JOIN incubations ON incubations.id = dna_extraction_protocols.lysis_id JOIN measurement_units ON measurement_units.id = incubations.temperature_unit_id \nWHERE protocols.code = ?'] [parameters: ('EPDqEP',)]

你知道我还能怎么得到我想要的吗?你知道吗


Tags: idunitcolumnkeysdnameasurementunitsprotocols
1条回答
网友
1楼 · 发布于 2024-06-28 15:16:35

问题的核心是您两次加入同一个表。在SQL land中,解决此问题的方法是将其中一个别名:

SELECT * FROM protocols
JOIN dna_extraction_protocols ON ...
JOIN measurement_units ON ...
JOIN incubations ON ...
JOIN measurement_units AS incubation_measurement_units ON incubation_measurement_units.id = incubations.temperature_unit_id

同样的道理:

sql_query = session.query(DNAExtractionProtocol, MeasurementUnit, Incubation) \
    .join(MeasurementUnit, ...) \
    .join(Incubation, ...) \
    .join(MeasurementUnit, ..., aliased=True) \
    .filter(tables[table].code == code)

如果需要从别名表中返回列或对别名表进行筛选,则会遇到问题,因为无法消除两者之间的歧义。在这种情况下,您需要连接到一个显式的^{}构造。你知道吗

IncubationMeasurementUnit = aliased(MeasurementUnit)
sql_query = session.query(DNAExtractionProtocol, MeasurementUnit, Incubation, IncubationMeasurementUnit) \
    .join(MeasurementUnit, ...) \
    .join(Incubation, ...) \
    .join(IncubationMeasurementUnit, ...) \
    .filter(tables[table].code == code)

相关问题 更多 >