2017-08-07 117 views
0

我试图运行一个查询,根据字典列表筛选结果。针对字典列表的Sqlalchemy查询

让我们更清晰......

我有一个表格标题,每个标题有一个版本字段

class Heading(Base): 
    id = Column(Integer, primary_key=True) 
    name = Column(String(50), nullable=False) 
    version = Column(Integer) 

在另一方面,我有字典,看起来像这样的列表(JSON格式化):

"headings": [ 
    { 
     "id": 1, 
     "version": 1 
    }, 
    { 
     "id": 2, 
     "version": 1 
    } 
] 

我想执行上排除行,其中在数据库中的版本是等于(JSON)列表中选择版本的标题表的查询。

我试图执行是这样的:

res = Heading.query.filter(~Heading.id.in_([d['id'] for d in headings if d['version'] == Heading.version])).all() 

与数据库看起来像这样(JSON再次格式化,不好意思):

[ 
{ 
    "id": 1, 
    "name": "Heading1", 
    "version": 2, 
}, 
{ 
    "id": 2, 
    "name": "Heading2", 
    "version": 1, 
} 
] 

但也无妨返回Heading2行。基本上,我希望查询返回在Json中未定义的所有行以及在数据库中具有较新版本的行。

我不知道我的问题是否足够清楚。 也许这是不正确的方法,请让我知道提前

感谢所有帮助

编辑: 生成的原始SQL是这样:

SELECT heading.id, heading.name, heading.version 
FROM heading 
WHERE heading.id = heading.id 

因此,有一个sqlalchemy查询明显的问题,但我不知道什么...

我认为它来自部分

if d['version'] == Heading.version 

但我不知道该如何重新制定这一条件的其他地方查询

+0

你可以发布原始SQL查询吗? –

回答

1

正如你怀疑问题出在

[... for ... if d['version'] == Heading.version] 

虽然d['version'] == Heading.version产生SQL表达式对象,然后Python使用它的真值进行过滤:

In [9]: bool(headings[0]['version'] == Heading.version) 
Out[9]: False 

等等你的列表理解导致一个空的列表。一个Heading.id可能永远不会在一个空列表,所以

~Heading.id.in_([]) 

会简单地计算为真:

In [10]: print(~Heading.id.in_([])) 
1 = 1 

鉴于您的数据库支持composite IN queries的解决方案是对比(ID,版本)元组:

In [9]: from sqlalchemy import tuple_ 

In [10]: session.query(Heading).\ 
    ...:  filter(~tuple_(Heading.id, Heading.version).in_(
    ...:   [(d['id'], d['version']) for d in headings])).\ 
    ...:  all() 
Out[10]: [<__main__.Heading at 0x7f840cc8ae48>] 

In [11]: _[0].name 
Out[11]: 'Heading1' 
+0

非常感谢您的回答,这比我找到的解决方案更加优雅。肯定会重用这些复合IN查询。 – CloC