我认为您的解决方案将产生不确定的结果,因为组中的行处于未指定的顺序,因此基于此,数组聚合和给定数组之间的比较可能会产生true或false:
[local]:5432 u@sopython*=> select group_id[local] u@sopython- > from multi_groups [local] u@sopython- > group by group_id[local] u@sopython- > having array_agg((atom_id, sequence)) = ARRAY[(1,3),(2,2),(3,1)]; group_id ---------- 2(1 row)[local]:5432 u@sopython*=> update multi_groups set atom_id = atom_id where atom_id = 2;UPDATE 2[local]:5432 u@sopython*=> select group_id from multi_groups group by group_idhaving array_agg((atom_id, sequence)) = ARRAY[(1,3),(2,2),(3,1)]; group_id ----------(0 rows)
您可以对两者都应用排序,也可以尝试完全不同的方法:可以使用关系除法来代替数组比较。
为了进行划分,您必须从
Entity记录列表中形成一个临时关系。同样,有很多方法可以解决这个问题。这是一个使用非嵌套数组的数组:
In [112]: vtm = select([ ...: func.unnest(postgresql.array([ ...: getattr(e, f) for e in values_to_match ...: ])).label(f) ...: for f in Entity._fields ...: ]).alias()
另一个使用联合:
In [114]: vtm = union_all(*[ ...: select([literal(e.atom_id).label('atom_id'), ...: literal(e.sequence).label('sequence')]) ...: for e in values_to_match ...: ]).alias()临时表也可以。
有了新的关系,您想找到答案“找到那些
multi_groups不存在的不在组中的实体”。这句话很可怕,但是很有意义:
In [117]: mg = aliased(MultiColumnGroups)In [119]: session.query(MultiColumnGroups.group_id). ...: filter(~exists(). ...: select_from(vtm). ...: where(~exists(). ...: where(MultiColumnGroups.group_id == mg.group_id). ...: where(tuple_(vtm.c.atom_id, vtm.c.sequence) == ...: tuple_(mg.atom_id, mg.sequence)). ...: correlate_except(mg))). ...: distinct(). ...: all() ...: Out[119]: [(2)]
另一方面,您也可以选择与给定实体的组的交集:
In [19]: gs = intersect(*[ ...: session.query(MultiColumnGroups.group_id). ...: filter(MultiColumnGroups.atom_id == vtm.atom_id, ...: MultiColumnGroups.sequence == vtm.sequence) ...: for vtm in values_to_match ...: ])In [20]: session.execute(gs).fetchall()Out[20]: [(2,)]
错误
ProgrammingError: (psycopg2.ProgrammingError) operator does not exist: record[] = integer[]LINE 3: ...gg((multi_groups.atom_id, multi_groups.sequence)) = ARRAY[AR... ^HINT: No operator matches the given name and argument type(s). You might need to add explicit type casts. [SQL: 'SELECt multi_groups.group_id AS multi_groups_group_id nFROM multi_groups GROUP BY multi_groups.group_id nHAVINg array_agg((multi_groups.atom_id, multi_groups.sequence)) = %(array_agg_1)s'] [parameters: {'array_agg_1': [[1, 3], [2, 2], [3, 1]]}] (Background on this error at: http://sqlalche.me/e/f405)是您如何
values_to_match首先将DB-
API驱动程序转换为列表(由于未知原因)然后将其转换为数组的结果。结果是一个整数数组的数组,而不是一个记录数组(int,int)。使用原始的DB-
API连接和游标,传递元组列表可以按预期工作。
在SQLAlchemy的,如果你包裹清单
values_to_match有
sqlalchemy.dialects.postgresql.array(),它可以作为你的意思是它的工作,但请记住,结果是不确定的。



