MySQL内部联接返回同一行的倍数
Posted
技术标签:
【中文标题】MySQL内部联接返回同一行的倍数【英文标题】:MySQL Inner Join Returning Multiples of the Same Row 【发布时间】:2014-08-20 06:43:38 【问题描述】:我有两个 mysql 表如下:
resource
-----------------------------------------------
id name group owner_id
-----------------------------------------------
1 MyResource1 hs 11
2 MyResource2 ms 24
3 MyResource3 ps 11
...
resource_access
-----------------------------------------------
id resource_id user_id
-----------------------------------------------
1 1 12
2 2 24
3 2 11
4 3 15
...
现在,第一个表当然是资源列表,以及owner_id
列中的各自所有者。第二个表是与另一个用户“共享”该资源的结果。表resource_access
可能包含带有user_id
的记录,这与owner_id
在resource_access
的一行中的owner_id
相同,这是来自所有者交换的混乱清理的结果。
我只想获取用户有权访问的任何资源的 ID、名称和组,无论他们是所有者还是已与他们共享。这是我对示例用户 (24) 的 MySQL 查询:
SELECT resource.id, resource.name, resource.group
FROM `resource`
INNER JOIN resource_access ON (
resource.owner_id='24'
OR (
resource_access.user_id='24' AND
resource_access.resource_id=resource.id
)
)
现在,它会多次返回资源号 2 的 id
、name
和 group
(例如 12 个)。有没有可能的原因?我已经尝试过 LEFT
和 RIGHT
加入并得到相同的结果。 resource
表中有很多记录,但没有一个与 id
为 2 的记录。resource_access
中没有重复的行与同一用户共享资源两次。
提前致谢。
【问题讨论】:
使用SELECT DISTINCT
删除重复项。否则,每个与他们共享的用户都会得到一行,因为JOIN
在两个表之间执行了交叉乘积。
【参考方案1】:
用途:
SELECT DISTINCT resource.id, resource.name, resource.group
删除重复项。
从概念上讲,内连接的工作方式是在两个表之间产生一个完全的叉积。此叉积包含输入表中每 pair 行的一行。然后它保留匹配所有ON
和WHERE
条件的行,并将其作为结果集返回。如果两个表之间有多个匹配的行,您将在结果集中获得多个行。
如果您从两个表中选择列,您会发现它们实际上不是同一行。它们只是具有来自resource
表的相同数据,但来自resource_access
表的数据不同。但是您没有在结果中显示后面的那些列。使用DISTINCT
会合并结果中的所有这些行。
【讨论】:
是的,我在上面的评论中说了原因。 假设您还在SELECT
子句中从 resource_access
返回了数据。然后你会看到这些行不是重复的,因为它们在这些其他列中是不同的。您只是没有返回这些列,因此您看不到它们是不同的行。【参考方案2】:
因为您只从resource
表中进行选择,我建议将条件放在where
子句中,而不是使用显式join
:
SELECT r.id, r.name, r.group
FROM `resource` r
WHERE r.owner_id='24' or
EXISTS (select 1
from resource_access ra
where ra.resource_id = r.id and
ra.user_id = '24'
);
按照这个逻辑,“加入”不能产生重复。
【讨论】:
你有一个额外的ON
行。
@Barmar 。 . .谢谢。【参考方案3】:
选择资源的所有权,然后将其与具有访问权限的资源联合。
生成的 user_id
列与您的 WHERE RA.user_id value
不同,这意味着资源是共享给他们的,而不是他们拥有资源。希望这会有所帮助。
SELECT resource.name,resource.group,resource.owner_id AS user_id
FROM resource
WHERE resource.owner_id = '11'
UNION
SELECT R.name,R.group,R.owner_id AS user_id
FROM resource_access RA
LEFT JOIN resource R
ON (R.id=RA.resource_id)
WHERE RA.user_id = '11';
【讨论】:
以上是关于MySQL内部联接返回同一行的倍数的主要内容,如果未能解决你的问题,请参考以下文章