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

时间:2014-06-29 22:40:51

标签: php mysql left-join inner-join right-join

我有两个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的记录,因为清理混乱来自业主交易所。

我只想获取用户有权访问的任何资源的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表中有许多记录,但没有id为2的记录。resource_access中没有重复的行与同一用户共享资源两次。

提前致谢。

3 个答案:

答案 0 :(得分:6)

使用:

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

删除重复项。

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

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

答案 1 :(得分:1)

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

有了这个逻辑,“加入”就不能产生重复。

答案 2 :(得分:0)

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