MySQL内部连接返回同一行的倍数


MySQL Inner Join Returning Multiples of the Same Row

我有两个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 可能包含resource_access行中user_id相当于owner_id的记录,这是由于所有者交换的混乱清理造成的。

我只是想获得用户可以访问的任何资源的id、名称和组,无论他们是所有者还是与他们共享。下面是我的MySQL查询示例用户(24):

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的idnamegroup(比如12次)。有可能的原因吗?我已经尝试了LEFTRIGHT连接,并得到相同的结果。resource表中有很多记录,但是没有2的id。在resource_access中没有重复的行与同一个用户共享资源两次。

使用说明:

SELECT DISTINCT resource.id, resource.name, resource.group

删除重复项。

内部连接在概念上的工作方式是在两个表之间产生一个完整的叉积。对于输入表中的每个行,这个交叉积包含一行。然后,它保留匹配所有ONWHERE条件的行,并将其作为结果集返回。如果两个表之间有多个匹配的行,您将在结果集中获得多个行。

如果您从两个表中选择列,您将看到它们实际上不是同一行。它们只是具有来自resource表的相同数据,但来自resource_access表的数据不同。但是您不会在结果中显示后面的列。使用DISTINCT合并结果中的所有这些行。

因为您只从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' 
             );

在此逻辑下,"join"不能进行产品重复。

选择资源的所有权,然后将其与具有访问权限的资源联合。结果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';