【问题标题】:SQLAlchemy return model from outerjoinSQLAlchemy 从外连接返回模型
【发布时间】:2015-07-10 01:08:10
【问题描述】:

给定一个模型:

class Model(Base):
    __tablename__ = 'dummy'

    insert_date = Column(Date())
    pk = Column(Integer())
    ...

我需要复制以下 sql 查询:

select a.* 
from (select * from dummy where insert_date = TODAY) a
left join (select distinct pk from dummy where insert_date < TODAY) b 
using (pk)
where b.(whatever) IS/IS NOT Null

但我需要 sqlalchemy 来返回对象,而不是列的元组(这是我目前正在使用的)。

换句话说,我基本上达到了,

"获取第一次插入的所有虚拟记录 昨天”

"获取昨天更新的所有虚拟记录"

取决于语句的 IS 或 IS NOT NULL 部分。每个 pk 将有多个条目。您不能依赖按更新日期进行过滤。 需要注意的是pk会是下一张表的主键,但不是当前表的主键。

例如,

假人:

Inserted Tuesday, pk=1, ....
Inserted Wednesday, pk=1, ....
Inserted Wednesday, pk=2, ....

pk=1 将返回 'IS NOT NULL' pk=2 将返回 'IS NULL'

我得到以下返回记录:

a = session.query(model).filter(model.date_retrieval==task_date).subquery()
b = session.query(model).filter(model.date_retrieval<task_date).subquery()
c = session.query(a, b).outerjoin(b, and_(a.c.pk==b.c.pk, a.c.seq==b.c.seq))  

返回:

c.all()[0] : 
(datetime.date(2015, 7, 1),
0,
1511,
u'431889',
u'7',
u'N',
u'0',
u'0',
u'0',
u'',
u'',
u'',
u'2',
u'5',
u'554428',
u'H',
u'9',
u'901',
datetime.date(2015, 6, 30),
0,
3487,
u'431889',
u'7',
u'N',
u'0',
u'0',
u'0',
u'',
u'',
u'',
u'2',
u'5',
u'554428',
u'H',
u'9',
u'901')

然后是类似

的东西
[indv for indv in c if indv[-1] ] and  [indv for indv in c if indv[-1] == None ]

将 IS NOT NULL 与 IS NULL 情况分开

编辑 1:

主键是由insert_date、insert_seq组成的复合键 ('2015-07-08', 0), ('2015-07-08', 1), ('2015-07-08', 2)...

【问题讨论】:

  • 不确定您的问题是什么。从标题(不是真的从描述中)我猜你想从你的join 语句中获取每个pk 的“模型”对象,因为你想更新它或类似的东西。我将通过pk 访问Model 以获取您需要更新的行。希望对您有所帮助。

标签: python sql sqlalchemy


【解决方案1】:

我认为你可以用下面的代码做你想做的事:

a = aliased(Model, name="a")
b = aliased(Model, name="b")
q = (
    session
    .query(a)
    .outerjoin(b, and_(a.pk == b.pk, b.insert_date < task_date))
    .filter(a.insert_date == task_date)
    .filter(b.pk == None)
    # or: .filter(b.pk != None)
)

它不会产生相同的sql,但我认为它在语义上是相同的。

另一种(在我看来,更简洁)的方法是使用exists~exists

q = (
    session
    .query(a)
    .filter(a.insert_date == task_date)
    .filter(
        exists(
        # or: ~exists(
            select([b.pk])
            .where(a.pk == b.pk)
            .where(b.insert_date < task_date)
        )
    )
)

【讨论】:

  • 我认为后者通常会更慢。在任何情况下,都达到了预期的结果。我无法查询 a 和 outerjoin b 因为我没有使用正确的“别名”方法。我正在使用子查询,并且还研究了 model.__table__.alias(name='a'),但两者都不起作用。无论如何,非常感谢。
猜你喜欢
  • 2020-07-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-08-27
  • 1970-01-01
  • 2014-03-10
  • 2022-01-24
  • 2013-03-13
相关资源
最近更新 更多