鉴于这3个简单的SQLAlchemy模型:
In [17]: df.val.cumprod()
Out[17]:
a 1
b 2
c 6
d 24
e 120
Name: val, dtype: int64
我不明白这个问题的原因:
class Customer(ModelBase):
__tablename__ = 'customers'
id = sa.Column(sa.Integer, primary_key=True)
uid = sa.Column(sa.Unicode, nullable=False, unique=True)
class Handset(ModelBase):
__tablename__ = 'handsets'
id = sa.Column(sa.Integer, primary_key=True)
imei = sa.Column(sa.Unicode(15), nullable=False, unique=True)
class Channel(ModelBase):
__tablename__ = 'channels'
id = sa.Column(sa.Integer, primary_key=True)
customer_id = sa.Column(sa.ForeignKey(Customer.id), nullable=False)
handset_id = sa.Column(sa.ForeignKey(Handset.id), nullable=False)
customer = relationship(Customer, backref='channels', lazy='joined')
handset = relationship(Handset, backref='channels', lazy='joined')
__table_args__ = (
sa.Index('uk_channels_customer_handset',
customer_id, handset_id,
unique=True),
)
如果有多个session.query(Channel).filter(Handset.imei == '1234', Customer.uid == 'test').one_or_none()
与multiple rows found
相关联,但Channel
与handset_id
相关联,则此customer_id
会执行c = aliased(Customer)
h = aliased(Handset)
session.query(Channel).enable_eagerloads(False).join(c).join(h).filter(
c.uid == 'test', h.imei == '1234',
).one_or_none()
执行,但此查询可以正常运行:
{{1}}
如何通过急切加载客户来加载频道&手持机?
答案 0 :(得分:4)
第一个查询在手机,客户和渠道之间产生隐式交叉连接(这是一个多行的来源)+ 2个左连接(来自客户和手机的急切加载),这可能不是您想要的:
In [7]: print(session.query(Channel).filter(Handset.imei == '1234', Customer.uid == 'test'))
SELECT channels.id AS channels_id, channels.customer_id AS channels_customer_id, channels.handset_id AS channels_handset_id, customers_1.id AS customers_1_id, customers_1.uid AS customers_1_uid, handsets_1.id AS handsets_1_id, handsets_1.imei AS handsets_1_imei
FROM handsets, customers, channels LEFT OUTER JOIN customers AS customers_1 ON customers_1.id = channels.customer_id LEFT OUTER JOIN handsets AS handsets_1 ON handsets_1.id = channels.handset_id
WHERE handsets.imei = ? AND customers.uid = ?
当您明确定义连接并禁用预先加载左连接时,第二个工作。第一个查询可以使用has()
:
In [17]: print(session.query(Channel).filter(Channel.handset.has(imei='1234'),
Channel.customer.has(uid='test')))
SELECT channels.id AS channels_id, channels.customer_id AS channels_customer_id, channels.handset_id AS channels_handset_id, customers_1.id AS customers_1_id, customers_1.uid AS customers_1_uid, handsets_1.id AS handsets_1_id, handsets_1.imei AS handsets_1_imei
FROM channels LEFT OUTER JOIN customers AS customers_1 ON customers_1.id = channels.customer_id LEFT OUTER JOIN handsets AS handsets_1 ON handsets_1.id = channels.handset_id
WHERE (EXISTS (SELECT 1
FROM handsets
WHERE handsets.id = channels.handset_id AND handsets.imei = ?)) AND (EXISTS (SELECT 1
FROM customers
WHERE customers.id = channels.customer_id AND customers.uid = ?))
从本质上讲,这将分别检查该通道是否存在具有给定谓词的手机和客户,然后将客户和手机连接到此通道。
您还可以通过an explicit join in the second query and to eager load using that指示SQLAlchemy使用contains_eager()
:
In [28]: print(session.query(Channel).\
join(c).join(h).\
options(contains_eager(Channel.handset, alias=h),
contains_eager(Channel.customer, alias=c)).\
filter(
c.uid == 'test', h.imei == '1234',
))
SELECT customers_1.id AS customers_1_id, customers_1.uid AS customers_1_uid, handsets_1.id AS handsets_1_id, handsets_1.imei AS handsets_1_imei, channels.id AS channels_id, channels.customer_id AS channels_customer_id, channels.handset_id AS channels_handset_id
FROM channels JOIN customers AS customers_1 ON customers_1.id = channels.customer_id JOIN handsets AS handsets_1 ON handsets_1.id = channels.handset_id
WHERE customers_1.uid = ? AND handsets_1.imei = ?
在我看来是更清洁的解决方案。