【问题标题】:Python SQLAlchemy: Filter joined tables with subqueriesPython SQLAlchemy:使用子查询过滤连接表
【发布时间】:2018-02-22 06:39:58
【问题描述】:

在 sqlalchemy 中,我为我的数据库定义了一个模型,在本例中是两个表“sample”和“experiment”,它们通过多对多关系相互链接:

class Sample(Base):
    __tablename__ = 'sample'

    id = Column(Integer, primary_key=True)
    name = Column(String)
    date = Column(String)

class Experiment(Base):
    __tablename__ = 'experiment'

    id = Column(Integer, primary_key=True)
    name = Column(String)
    description = Column(String)
    result = Column(String)

    samples = relationship('Sample', secondary='sample_has_experiment', backref="experiments")

t_sample_has_experiment = Table(
    'sample_has_experiment', metadata,
    Column('sample_id', ForeignKey('sample.id'), primary_key=True, nullable=False, index=True),
    Column('experiment_id', ForeignKey('experiment.id'), primary_key=True, nullable=False, index=True)
)

在我的数据库中,我有一个样本“Dilithium”,在实验中有两个实验“Cold fusion”和“Worm hole”。

我尝试通过连接到示例表来查询“虫洞”实验:

samples = s.query(Obj.Sample).join(Obj.Sample.experiments).\
    filter(Obj.Experiment.name == "Worm hole").all()


for sample in samples:
    for experiment in sample.experiments:
        print(experiment.name)

但结果我仍然得到“虫洞”和“冷聚变”两个实验。所以看起来过滤没有应用。如何过滤我只收到“虫洞”实验对象的方式?谢谢。

@Dublicate:确实它看起来像同一个问题,但给定的答案并不能解决我的问题。在我看来,我建议的查询与建议的答案完全相同。

【问题讨论】:

  • i 中的for experiment in i.experiments 是什么?我想应该是sample...
  • 谢谢,你说得对,只是创建这个例子时打错了。
  • 实际上,建议的答案正是我用于查询的答案,但在我的情况下,结果不知何故未被过滤。

标签: python python-3.x sqlalchemy


【解决方案1】:

你的代码说的是:

  • 对于作为虫洞实验一部分的所有样本

    • 打印样本所属的所有实验

也就是说,给定一个特定样本,sample.experiments 始终是该样本所属的所有实验,而不仅仅是您通过该样本获得的实验。

如果您添加一个不属于虫洞实验的新样本,您会看到这一点。它不应出现在您的查询中。

所以,我对“为什么我的查询没有对连接进行过滤”的回答是我强烈怀疑它是。

如果你想要虫洞实验中的样本对象,那么类似

samples = session.query(Experiments).filter_by(name = 'wormhole').one().samples

【讨论】:

  • 谢谢,我现在可以看到问题了。其实,我想反过来。我有一个特定的样本,我想查看/过滤为此样本所做的实验。你的建议的问题是,如果我先选择实验然后查看样本,我仍然需要过滤结果,因为一个实验可以分配多个样本。
  • 好的。我想我已经回答了你提出的问题。即使给出了您的评论,您希望做什么也不够清楚,如果您提出这个问题,我会尝试回答。
【解决方案2】:

编辑:其实我一开始就意识到我的错误是什么。我必须查询所有表,然后应用连接和过滤器:

qry = s.query(Obj.Sample, Obj.Experiment).\ # Query both tables!
    filter(Obj.Sample.name == "...").\
    filter(Obj.Experiment.name == "...").\
    join(Obj.Experiment, Obj.Sample.experiments).all()

替代方式:使用子查询会导致所需的行为:

wormhole_exp = s.query(Obj.Experiment).filter(Obj.Experiment.name == "wormhole").subquery()

print(s.query(Obj.Sample, wormhole_exp).join(wormhole_exp, Obj.Sample.experiments).one())

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-06-09
    • 2020-11-04
    • 2016-05-08
    • 2015-05-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-18
    相关资源
    最近更新 更多