无重复地连接涉及 LEFT JOIN 的四个表
Join four tables involving LEFT JOIN without duplicates
我想加入四个 table 具有 null 值且不重复,然后将其转换为 SQLAlchemy 查询。
table是(简体):
Category(id, name)
Task(id, category.id, name)
User(id, name)
和多对多table:
Solved(task.id, user.id)
我想获取所有任务及其类别和一个包含解决该任务的特定用户的列:
+---------------+-----------+-----------+
| category.name | task.name | user.name |
+---------------+-----------+-----------+
| abc | abctask1 | <null> |
| abc | abctask2 | luke |
| def | deftask1 | <null> |
| ghi | ghitask1 | <null> |
| ghi | ghitask2 | luke |
+---------------+-----------+-----------+
目前我有 3 到 4 个单独的 SQLAlchemy 查询来执行该任务。如果可能的话,应该合并成一个查询,避免数据库读取过多。
到目前为止我有:
SELECT DISTINCT
cat.name, t.name, u.name
FROM
Task t
JOIN
Category cat ON cat.id = t.category_id
LEFT JOIN
Solved s ON s.task_id = t.id
LEFT JOIN
User u ON s.user_id = u.id AND
u.name = 'luke'
ORDER BY
cat.name
但是,尽管 DISTINCT
,我从给定用户的所有行中得到了重复项:
+---------------+-----------+-----------+
| category.name | task.name | user.name |
+---------------+-----------+-----------+
| abc | abctask1 | <null> |
| abc | abctask2 | luke |
| abc | abctask2 | <null> | <-- duplicate
| def | deftask1 | <null> |
| ghi | ghitask1 | <null> |
| ghi | ghitask2 | luke |
| ghi | ghitask2 | <null> | <-- duplicate
+---------------+-----------+-----------+
是否有可能通过一次查询获得此 table 并将其转换为 SQLAlchemy?
问题来自您的数据,即您可能有 2 个名为 abctask2/ghitask2 的任务。也许您应该对任务名称施加约束。您的查询很好。
http://sqlfiddle.com/#!9/c4647c/4
尝试检查
SELECT category_id, name ,count(*) from TASK GROUP BY category_id, name HAVING COUNT(*)<>1
你有两个LEFT JOINS
:
- 第一个左连接可以连接到
solved
中的多行。比如说,'jane' 和 'luke' 解决了任务。
- 左边第二个加入只能加入名为'luke'的用户(加入条件为'luke'!)。
你仍然得到 both 行,'jane' 只是没有显示,连接条件过滤掉了她,但是LEFT JOIN
无论如何都会保留结果中的行并附加 NULL 值。
您可以通过使用 括号 和 [INNER] JOIN
而不是 solved
和 [=18 之间的 LEFT JOIN
来实现您想要的=]. The manual:
Use parentheses if necessary to determine the order of nesting. In the
absence of parentheses, JOIN
s nest left-to-right.
SELECT c.name AS cat_name, t.name AS task_name, u.name AS user_name
FROM task t
JOIN category c ON cat.id = t.category_id
LEFT JOIN
(solved s JOIN users u ON u.id = s.user_id AND u.name = 'luke') ON s.task_id = t.id
ORDER BY 1, 2, 3;
使用table名称users
代替保留字user
.
假设 users.name
被定义为 unique 或者您可以有多个名为 'luke'.
[= 的用户68=]
如果solved
中的(task.id, users.id)
定义为UNIQUE
或PRIMARY KEY
,则根本不需要DISTINCT
。
生成的查询不仅正确,而且速度更快。
上述查询的SqlAlchemy版本: (contributed by @van)
这假设 Category
、Task
和 User
被映射 类,而 solved
是 Table
的实例(只是一个关联 table 如代码示例所示 Many to Many):
user_name = 'luke'
q = (session.query(Category.name, Task.name, User.name)
.select_from(Task)
.join(Category)
.outerjoin(
join(solved, User,
(solved.c.user_id == User.id) & (User.name == user_name),
))
.order_by(Category.name, Task.name, User.name)
)
我想加入四个 table 具有 null 值且不重复,然后将其转换为 SQLAlchemy 查询。
table是(简体):
Category(id, name)
Task(id, category.id, name)
User(id, name)
和多对多table:
Solved(task.id, user.id)
我想获取所有任务及其类别和一个包含解决该任务的特定用户的列:
+---------------+-----------+-----------+
| category.name | task.name | user.name |
+---------------+-----------+-----------+
| abc | abctask1 | <null> |
| abc | abctask2 | luke |
| def | deftask1 | <null> |
| ghi | ghitask1 | <null> |
| ghi | ghitask2 | luke |
+---------------+-----------+-----------+
目前我有 3 到 4 个单独的 SQLAlchemy 查询来执行该任务。如果可能的话,应该合并成一个查询,避免数据库读取过多。
到目前为止我有:
SELECT DISTINCT
cat.name, t.name, u.name
FROM
Task t
JOIN
Category cat ON cat.id = t.category_id
LEFT JOIN
Solved s ON s.task_id = t.id
LEFT JOIN
User u ON s.user_id = u.id AND
u.name = 'luke'
ORDER BY
cat.name
但是,尽管 DISTINCT
,我从给定用户的所有行中得到了重复项:
+---------------+-----------+-----------+
| category.name | task.name | user.name |
+---------------+-----------+-----------+
| abc | abctask1 | <null> |
| abc | abctask2 | luke |
| abc | abctask2 | <null> | <-- duplicate
| def | deftask1 | <null> |
| ghi | ghitask1 | <null> |
| ghi | ghitask2 | luke |
| ghi | ghitask2 | <null> | <-- duplicate
+---------------+-----------+-----------+
是否有可能通过一次查询获得此 table 并将其转换为 SQLAlchemy?
问题来自您的数据,即您可能有 2 个名为 abctask2/ghitask2 的任务。也许您应该对任务名称施加约束。您的查询很好。
http://sqlfiddle.com/#!9/c4647c/4
尝试检查
SELECT category_id, name ,count(*) from TASK GROUP BY category_id, name HAVING COUNT(*)<>1
你有两个LEFT JOINS
:
- 第一个左连接可以连接到
solved
中的多行。比如说,'jane' 和 'luke' 解决了任务。 - 左边第二个加入只能加入名为'luke'的用户(加入条件为'luke'!)。
你仍然得到 both 行,'jane' 只是没有显示,连接条件过滤掉了她,但是LEFT JOIN
无论如何都会保留结果中的行并附加 NULL 值。
您可以通过使用 括号 和 [INNER] JOIN
而不是 solved
和 [=18 之间的 LEFT JOIN
来实现您想要的=]. The manual:
Use parentheses if necessary to determine the order of nesting. In the absence of parentheses,
JOIN
s nest left-to-right.
SELECT c.name AS cat_name, t.name AS task_name, u.name AS user_name
FROM task t
JOIN category c ON cat.id = t.category_id
LEFT JOIN
(solved s JOIN users u ON u.id = s.user_id AND u.name = 'luke') ON s.task_id = t.id
ORDER BY 1, 2, 3;
使用table名称
users
代替保留字.user
假设
[= 的用户68=]users.name
被定义为 unique 或者您可以有多个名为 'luke'.如果
solved
中的(task.id, users.id)
定义为UNIQUE
或PRIMARY KEY
,则根本不需要DISTINCT
。
生成的查询不仅正确,而且速度更快。
上述查询的SqlAlchemy版本: (contributed by @van)
这假设 Category
、Task
和 User
被映射 类,而 solved
是 Table
的实例(只是一个关联 table 如代码示例所示 Many to Many):
user_name = 'luke'
q = (session.query(Category.name, Task.name, User.name)
.select_from(Task)
.join(Category)
.outerjoin(
join(solved, User,
(solved.c.user_id == User.id) & (User.name == user_name),
))
.order_by(Category.name, Task.name, User.name)
)