如何使用SQLAlchemy会话确定一个PGArray是否包含在另一个PGArray中?

时间:2009-06-05 19:40:14

标签: python arrays postgresql sqlalchemy

我有一个像这样的SqlAlchemy表:

table = sql.Table('treeItems', META,
    sql.Column('id', sql.Integer(), primary_key=True),
    sql.Column('type', sql.String, nullable=False),
    sql.Column('parentId', sql.Integer, sql.ForeignKey('treeItems.id')),
    sql.Column('lineage', PGArray(sql.Integer)),
    sql.Column('depth', sql.Integer),
)

映射到像这样的对象:

orm.mapper(TreeItem, TreeItem.table, polymorphic_on=TreeItem.table.c.type, polymorphic_identity='TreeItem')

我想选择给定节点的任何子节点,所以我正在寻找的是这样的SQL(对于pk = 2的父节点):

SELECT *
FROM "treeItems"
WHERE ARRAY[2] <@ "treeItems".lineage AND "treeItems".id != 2
ORDER BY "treeItems".lineage

这是我用来试图获得上述SQL的SqlAlchemy / Python代码,但运气不佳:

arrayStr = 'ARRAY[%s]' % ','.join([str(i) for i in self.lineage])
lineageFilter = expr.text('%s <@ %s' % (arrayStr, TreeItem.table.c.lineage))
query = SESSION.query(TreeItem).filter(expr.and_(lineageFilter, TreeItem.table.c.id!=self.id))

但这是我最终得到的SQL(请注意where子句中treeItems表名称周围缺少引号):

SELECT "treeItems".id AS "treeItems_id", "treeItems".type AS "treeItems_type", "treeItems"."parentId" AS "treeItems_parentId", "treeItems".lineage AS "treeItems_lineage", "treeItems".depth AS "treeItems_depth"
FROM "treeItems"
WHERE ARRAY[2] <@ treeItems.lineage AND "treeItems".id != %(id_1)s

所以,现在问题是:

有没有比使用text()表达式更好的方法/在SqlAlchemy中是否有一个运算符或表达式可以&lt; @ with PGArray?

如果我必须使用text()表达式,如何在表名周围显示引号?

谢谢大家!

2 个答案:

答案 0 :(得分:4)

SQLAlchemy的子句元素具有自定义运算符的.op()方法。不可用的是数组文字的特殊子句。您可以使用literal_column指定数组文字:

print sql.literal_column('ARRAY[2]').op('<@')(table.c.lineage)
# ARRAY[2] <@ "treeItems".lineage

如果您想要更好的API数组文字,那么您可以使用SQLAlchemy 0.5.4中添加的sqlalchemy.ext.compiler模块创建它。

答案 1 :(得分:0)

在这个特殊情况下,我注意到SQL中的引用是由于我使用的是混合大小写的表名。将表名从'treeItems'转换为'tree_items'解决了引用问题,我能够使我的文本表达式起作用:

expr.text('%s <@ %s' % (arrayStr, TreeItem.table.c.lineage))

这是一个修复,很高兴知道需要引用混合案例表名称,但蚂蚁的回答仍然是解决问题的正确方法。