SQLalchemy select 所有不存在连接的地方 mysql 使用 orm

Sqlalchemy select all where join not exists mysql using orm

我们有两个表:用户和权限

我们想要 select 所有没有 "guest" 权限的用户。现在,用户可以拥有多个权限(不仅仅是 1 个),所以简单地查询 !"guest" 是行不通的。这是我们的查询现在的样子:

query = session.query(Users).join(Permission, and_(
        Permission.userId == theUser.uid, Permission.deviceId== theDevice.uid))
query.join(Permission).filter(~exists().where(and_(Permission.level==SqlConstants.PermissionLevels.GUEST, Users.uid == Permission.userId)))

我不确定第一行中的连接是否与我们遇到的问题相关,但我们正在使用它,所以我将其包含在这里。 (如果它不相关,我会编辑它。)

以上returns以下异常:

returned no FROM clauses due to auto-correlation; specify correlate(<tables>) to control correlation manually.

我从以下 SO post 中收集了这个模式: Using NOT EXISTS clause in sqlalchemy ORM query

以及来自 sqlalchemy 文档(关于不存在的内容很浅): http://docs.sqlalchemy.org/en/rel_1_0/orm/query.html

我不清楚自己哪里做错了,也不清楚是否有更好的方法。

我不确定我是否理解了您的问题,主要是因为我想出的解决方案非常简单。我会试一试,无论如何我希望它能以某种方式帮助你。

我能够轻松地重现您在使用 exists 时遇到的异常。我认为这是因为在 where 参数中您混合了 join 中两个 table 的列。如果你或多或少像这样重写它就不会给出异常,

sq = session.query(Users.pk).join(Permission).filter(Permission.level==SqlConstants.PermissionLevels.GUEST)
q = session.query(Users).join(Permission).filter(~sq.exists())

然而它不起作用,因为一旦在 Permission 中有 1 个具有 GUEST 级别的寄存器,查询将不会给出任何结果。

但为什么不这样重写呢?

sq = session.query(Users.pk).join(Permission).filter(Permission.level==SqlConstants.PermissionLevels.GUEST)
q = session.query(Users).filter(~Users.pk.in_(sq))

在我的试验中,如果我正确理解了你的问题,它就会起作用。

仅供参考,这是我使用的玩具示例,其中 table A 对应于 UsersB 对应于 PermissionB.attr 将存储权限级别。

In [2]:

class A(Base):
    __tablename__ = 'A'

    pk = Column('pk', Integer, primary_key=True)
    name = Column('name', String)


class B(Base):
    __tablename__ = 'B'

    pk = Column('pk', Integer, primary_key=True)
    fk = Column('fk', Integer, ForeignKey('A.pk'))
    attr = Column('attr', Integer)

    a = relationship("A", backref='B')

这是我插入的数据,

In [4]:

q = session.query(B)
print(q)
for x in q.all():
    print(x.pk, x.fk, x.attr)

q = session.query(A)
print(q)
for x in q.all():
    print(x.pk, x.name)
​
SELECT "B".pk AS "B_pk", "B".fk AS "B_fk", "B".attr AS "B_attr" 
FROM "B"
1 1 1
2 1 2
3 2 0
4 2 4
5 1 4
SELECT "A".pk AS "A_pk", "A".name AS "A_name" 
FROM "A"
1 one
2 two
3 three

这是查询的结果,

In [16]:

from sqlalchemy import exists, and_, tuple_
sq = session.query(A.pk).join(B).filter(B.attr==2)
print(sq)
q = session.query(A).filter(~A.pk.in_(sq))
print(q)
​
for x in q.all():
    print(x.pk, x.name)
SELECT "A".pk AS "A_pk" 
FROM "A" JOIN "B" ON "A".pk = "B".fk 
WHERE "B".attr = :attr_1
SELECT "A".pk AS "A_pk", "A".name AS "A_name" 
FROM "A" 
WHERE "A".pk NOT IN (SELECT "A".pk AS "A_pk" 
FROM "A" JOIN "B" ON "A".pk = "B".fk 
WHERE "B".attr = :attr_1)
2 two
3 three

希望对您有所帮助!