Python 带outerjoin的查询(模型)sqlalchemy具有隐式的distinct?
考虑以下模型:Python 带outerjoin的查询(模型)sqlalchemy具有隐式的distinct?,python,sqlalchemy,flask-sqlalchemy,Python,Sqlalchemy,Flask Sqlalchemy,考虑以下模型: class Order(db.Model): id = db.Column(db.Integer, primary_key=True) status = db.Column(db.Enum('Ordered', 'Delivered'), default='Ordered', nullable=False) skus = db.relationship('SKU', order_by='SKU.index', back_populates='order',
class Order(db.Model):
id = db.Column(db.Integer, primary_key=True)
status = db.Column(db.Enum('Ordered', 'Delivered'), default='Ordered', nullable=False)
skus = db.relationship('SKU', order_by='SKU.index', back_populates='order', passive_deletes=True)
class SKU(db.Model):
id = db.Column(db.Integer, primary_key=True)
order_id = db.Column(db.Integer, db.ForeignKey('order.id', onupdate='CASCADE', ondelete='CASCADE'), nullable=False)
order = db.relationship('Order', lazy='joined', back_populates='skus', innerjoin=True)
index = db.Column(db.Integer)
supplier = db.Column(db.Integer)
(db
对象是SQLAlchemy
中的SQLAlchemy
的实例)
测试数据为三个SKU,按单个顺序排列:
+----+---------+
| id | status |
+----+---------+
| 10 | Ordered |
+----+---------+
+----+----------+-------+----------+
| id | order_id | index | supplier |
+----+----------+-------+----------+
| 28 | 10 | 0 | 10 |
| 29 | 10 | 1 | 10 |
| 30 | 10 | 2 | 10 |
+----+----------+-------+----------+
有人会认为,对SKU
使用显式外部联接Order
将产生笛卡尔积并返回3行,这是不正确的。这将打印单个“已订购”:
尽管如此,还是生成了正确的查询(并按预期返回3行):
我猜SQLAlchemy会以某种方式检测重复的Order对象并将其从最终列表中删除。但这有记录吗?这背后的原因是什么
同时,查询状态字段没有这个问题:3行打印在这里:
statuses = (db.session.query(Order.status).outerjoin(SKU)
.filter(SKU.supplier == 10).all())
for (status, ) in statuses:
print status
如果只是查询一个实体,并且您只是请求订单实体,那么重复的实体将根据标识/主键被剔除,这是正确的。例如,与带有实体(订单,SKU)的订单.query.outerjoin(SKU)…进行比较。。记不清是否记录了这些信息,但将尝试查找这些信息。理由可能是,由于返回的实体无论如何都是标识映射的,因此具有重复项的列表只包含对同一对象的多个引用,如果只是查询实体,返回此类重复项是没有意义的。@IljaEverilä,是的,你说得对。用实体(订单、SKU)添加
,
并用替换订单中(订单、SKU)的循环:
解决了问题(至少对于测试用例)。不过,我将坚持显式字段查询。
SELECT `order`.id AS order_id, `order`.status AS order_status
FROM `order` LEFT OUTER JOIN `SKU` ON `order`.id = `SKU`.order_id
WHERE `SKU`.supplier = %(supplier_1)s
statuses = (db.session.query(Order.status).outerjoin(SKU)
.filter(SKU.supplier == 10).all())
for (status, ) in statuses:
print status