SQLAlchemy从outerjoin

时间:2015-07-09 04:53:27

标签: python sql sqlalchemy

给出一个模型:

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来返回对象,而不是列的元组(这是我目前正在使用的)。

用语言来说,我基本上实现了,

  

&#34;获取第一次插入的所有虚拟记录   昨天&#34;

  

&#34;获取昨天更新的所有虚拟记录&#34;

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

例如,

in dummy:

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

pk = 1将返回&#39; IS NOT NULL&#39; pk = 2将返回&#39; IS NULL&#39;

我已经得到以下内容来返回记录:

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 NULL情况中划分IS NOT NULL

编辑1:

主键是由insert_date,insert_seq组成的复合键 (&#39; 2015-07-08&#39;,0),(&#39; 2015-07-08&#39;,1),(&#39; 2015-07-08&#39;,2) ...

1 个答案:

答案 0 :(得分: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)
        )
    )
)