如何强制 SQLAlchemy ORM 在子查询中包含 table?
How do I force SQLAlchemy ORM to include table in subquery?
我有两个 tables 用户和访客,内容如下:
用户:
+----+-------------+
| id | email |
+----+-------------+
| 1 | a.b@foo.com |
| 2 | b.c@bar.com |
+----+-------------+
访客:
+----+---------+------+
| id | user_id | addr |
+----+---------+------+
| 1 | NULL | 1 |
| 2 | NULL | 2 |
| 3 | NULL | 1 |
| 4 | NULL | 2 |
| 5 | NULL | 3 |
| 6 | 1 | 4 |
| 7 | NULL | 5 |
| 8 | NULL | 6 |
| 9 | 2 | 2 |
+----+---------+------+
我想获取 table 访问者 的所有 ID,这些 ID 不包含在地址列表中,这些地址链接到存储在 table 用户.
例如:
SELECT visitors.id
FROM visitors
WHERE visitors.addr NOT IN (
SELECT DISTINCT visitors.addr
FROM user, visitors
WHERE user.email LIKE '%bar%' AND visitors.user_id = user.id
)
内部 select 语句将 return addr 2 因此外部语句将 return 6 行的访问者 ID '有 add == 2(即除了 2、4 和 9 之外的所有)。
我试着用这个 SQLalchemy 语句来做到这一点:
subquery = (
session.query(Visitors.addr).distinct()
.filter(User.email.like('%bar%'), Visitors.user_id == User.id)
.subquery()
)
mainquery = session.query(Visitors.id).filter(Visitors.addr.notin_(subquery))
这是由 SQLalchemys ORM 创建的 SQL 语句:
SELECT visitors.id AS visitors_id
FROM visitors
WHERE visitors.addr NOT IN (SELECT DISTINCT visitors.addr
FROM user
WHERE user.email LIKE ? AND visitors.user_id = user.id)
关键区别在于子查询不再包含 FROM 子句中的访问者,缺少 table 意味着 visitor.id 2 和 4 是 returned,即使它们已分配地址 2。有没有办法强制 SQLAlchemy 在 FROM 子句中包含给定的 table,或者我应该尝试使用 JOIN 来获得相同的结果?
编辑:使用的 SQLAlchemy 版本是 1.3.20。从那时起,我将其更新为 1.4.23,以便能够按照@ian-wilson 的建议使用 scalar_subquery。
使用的数据库分别是 SQLite 3.35.5 和 MySQL 5.7.34。
使用 scalar_subquery 函数没有解决我的问题,对子查询使用连接可以。
我会像你提到的那样在这里使用连接,但你也应该考虑尝试 scalar_subquery
(1.4) 或 as_scalar
(<1.4) 来生成 in_
子句。
subquery = session.query(
Visitors.addr.distinct()
).join(
User,
Visitors.user_id == User.id
).filter(
User.email.like('%bar%')
).scalar_subquery()
mainquery = session.query(Visitors.id).filter(Visitors.addr.notin_(subquery))
https://docs.sqlalchemy.org/en/14/orm/query.html#sqlalchemy.orm.Query.scalar_subquery
我有两个 tables 用户和访客,内容如下:
用户:
+----+-------------+
| id | email |
+----+-------------+
| 1 | a.b@foo.com |
| 2 | b.c@bar.com |
+----+-------------+
访客:
+----+---------+------+
| id | user_id | addr |
+----+---------+------+
| 1 | NULL | 1 |
| 2 | NULL | 2 |
| 3 | NULL | 1 |
| 4 | NULL | 2 |
| 5 | NULL | 3 |
| 6 | 1 | 4 |
| 7 | NULL | 5 |
| 8 | NULL | 6 |
| 9 | 2 | 2 |
+----+---------+------+
我想获取 table 访问者 的所有 ID,这些 ID 不包含在地址列表中,这些地址链接到存储在 table 用户.
例如:
SELECT visitors.id
FROM visitors
WHERE visitors.addr NOT IN (
SELECT DISTINCT visitors.addr
FROM user, visitors
WHERE user.email LIKE '%bar%' AND visitors.user_id = user.id
)
内部 select 语句将 return addr 2 因此外部语句将 return 6 行的访问者 ID '有 add == 2(即除了 2、4 和 9 之外的所有)。 我试着用这个 SQLalchemy 语句来做到这一点:
subquery = (
session.query(Visitors.addr).distinct()
.filter(User.email.like('%bar%'), Visitors.user_id == User.id)
.subquery()
)
mainquery = session.query(Visitors.id).filter(Visitors.addr.notin_(subquery))
这是由 SQLalchemys ORM 创建的 SQL 语句:
SELECT visitors.id AS visitors_id
FROM visitors
WHERE visitors.addr NOT IN (SELECT DISTINCT visitors.addr
FROM user
WHERE user.email LIKE ? AND visitors.user_id = user.id)
关键区别在于子查询不再包含 FROM 子句中的访问者,缺少 table 意味着 visitor.id 2 和 4 是 returned,即使它们已分配地址 2。有没有办法强制 SQLAlchemy 在 FROM 子句中包含给定的 table,或者我应该尝试使用 JOIN 来获得相同的结果?
编辑:使用的 SQLAlchemy 版本是 1.3.20。从那时起,我将其更新为 1.4.23,以便能够按照@ian-wilson 的建议使用 scalar_subquery。 使用的数据库分别是 SQLite 3.35.5 和 MySQL 5.7.34。 使用 scalar_subquery 函数没有解决我的问题,对子查询使用连接可以。
我会像你提到的那样在这里使用连接,但你也应该考虑尝试 scalar_subquery
(1.4) 或 as_scalar
(<1.4) 来生成 in_
子句。
subquery = session.query(
Visitors.addr.distinct()
).join(
User,
Visitors.user_id == User.id
).filter(
User.email.like('%bar%')
).scalar_subquery()
mainquery = session.query(Visitors.id).filter(Visitors.addr.notin_(subquery))
https://docs.sqlalchemy.org/en/14/orm/query.html#sqlalchemy.orm.Query.scalar_subquery