在联接的 table 中为 SQL 中的每个 ID 返回一个结果
Returning one result per id in SQL in a joined table
我有一个 table 用户。
users
| user_id | name |
| ------- | ------ |
| 1 | Jerry |
| 2 | George |
| 3 | Elaine |
| 4 | Kramer |
我有一个 table 将角色链接到用户,并且角色是在树上分配的。
user_roles
| user_id | role_id | tree_id |
| ------- | ------- | ------- |
| 1 | 5 | 1 |
| 1 | 5 | 2 |
| 2 | 6 | 1 |
| 3 | 7 | 1 |
| 4 | 8 | 1 |
我只需要 return 在某个 tree_id 分配用户角色的结果,所以我正在检查所有角色和树。最后,我希望每个用户 return 一行。
我正在使用 Knex 并执行如下查询:
knex('users')
.leftJoin('user_roles', {'user.user_id': 'user_roles.user_id'})
.whereIn('user_roles.tree_id', arrayOfTreeIds)
.andWhere(moreFilters)
SELECT *
FROM users
LEFT JOIN user_roles on users.user_id = user_roles.user_id
WHERE user_roles.tree_id in (1, 2, 3)
不过,我得到了五个结果,而不是四个。如果我尝试 SELECT DISTINCT
,它告诉我我需要 GROUP BY
,但我无法让它工作。我需要做什么才能让每个用户 ID 只获得一个结果?
您有一个用户在两个不同的 tree_id
上匹配,所以这会增加行数。
在纯 SQL 中,您可以使用 exists
而不是 join
:
SELECT *
FROM users u
WHERE EXISTS (
SELECT 1
FROM user_roles ur
WHERE ur.user_id = u.user_id AND ur.tree_id in (1, 2, 3)
)
另一种选择是聚合:
SELECT u.*
FROM users u
INNER JOIN user_roles ur on u.user_id = ur.user_id
WHERE ur.tree_id in (1, 2, 3)
GROUP BY u.user_id
我将 LEFT JOIN
更改为 INNER JOIN
,因为从本质上讲,这就是您想要的(以及您的原始查询所做的)。
您甚至可以使用字符串聚合列出匹配的角色:
SELECT u.*, STRING_AGG(ur.tree_id::text, ',' ORDER BY ur.tree_id) tree_ids
FROM users u
INNER JOIN user_roles ur on u.user_id = ur.user_id
WHERE ur.tree_id in (1, 2, 3)
GROUP BY u.user_id
免责声明:我不知道如何在 knex 中写这个!
我有一个 table 用户。
users
| user_id | name |
| ------- | ------ |
| 1 | Jerry |
| 2 | George |
| 3 | Elaine |
| 4 | Kramer |
我有一个 table 将角色链接到用户,并且角色是在树上分配的。
user_roles
| user_id | role_id | tree_id |
| ------- | ------- | ------- |
| 1 | 5 | 1 |
| 1 | 5 | 2 |
| 2 | 6 | 1 |
| 3 | 7 | 1 |
| 4 | 8 | 1 |
我只需要 return 在某个 tree_id 分配用户角色的结果,所以我正在检查所有角色和树。最后,我希望每个用户 return 一行。
我正在使用 Knex 并执行如下查询:
knex('users')
.leftJoin('user_roles', {'user.user_id': 'user_roles.user_id'})
.whereIn('user_roles.tree_id', arrayOfTreeIds)
.andWhere(moreFilters)
SELECT *
FROM users
LEFT JOIN user_roles on users.user_id = user_roles.user_id
WHERE user_roles.tree_id in (1, 2, 3)
不过,我得到了五个结果,而不是四个。如果我尝试 SELECT DISTINCT
,它告诉我我需要 GROUP BY
,但我无法让它工作。我需要做什么才能让每个用户 ID 只获得一个结果?
您有一个用户在两个不同的 tree_id
上匹配,所以这会增加行数。
在纯 SQL 中,您可以使用 exists
而不是 join
:
SELECT *
FROM users u
WHERE EXISTS (
SELECT 1
FROM user_roles ur
WHERE ur.user_id = u.user_id AND ur.tree_id in (1, 2, 3)
)
另一种选择是聚合:
SELECT u.*
FROM users u
INNER JOIN user_roles ur on u.user_id = ur.user_id
WHERE ur.tree_id in (1, 2, 3)
GROUP BY u.user_id
我将 LEFT JOIN
更改为 INNER JOIN
,因为从本质上讲,这就是您想要的(以及您的原始查询所做的)。
您甚至可以使用字符串聚合列出匹配的角色:
SELECT u.*, STRING_AGG(ur.tree_id::text, ',' ORDER BY ur.tree_id) tree_ids
FROM users u
INNER JOIN user_roles ur on u.user_id = ur.user_id
WHERE ur.tree_id in (1, 2, 3)
GROUP BY u.user_id
免责声明:我不知道如何在 knex 中写这个!