【问题标题】:One to many link table causing duplicate rows returned一对多链接表导致返回重复行
【发布时间】:2010-02-04 16:56:56
【问题描述】:

到目前为止,我所看到的一切都是关于自动删除数据库中的重复条目。我想在开头强调数据库中没有重复数据。我还要从这样一个事实开始,即我仍在学习 RDBMS 设计、规范化、关系,最重要的是 SQL!

我有一个客户表,其中包含一个 clientid (PK) 和一个 client_name。我有一个角色表,其中包含一个角色 ID (PK) 和一个角色名称。任何客户端都可以有多个与之关联的角色。所以我创建了一个client_role_link 表,其中clientid 和roleid 作为两个字段。然后我运行这个:

SELECT client.client_name, role.role_name FROM client 
  LEFT JOIN client_role_link ON client_role_link.clientid=client.clientid 
  LEFT JOIN role ON client_role_link.roleid=role.roleid 
  WHERE (role.roleid='1' OR role.roleid='2')

假设我有一个客户端,它有两个与之关联的角色(角色“1”和“2”)。此查询返回两行,每个角色一个。当我得到这些结果时,我正在使用while 循环循环遍历结果并将它们输出到<select> 列表中。然后它会导致两个<option> 列出相同的客户端。

我理解为什么我的查询返回两行,这是有道理的。所以这里有两个问题:

  1. 我应该使用更好的数据库/表设计还是更优化的查询?
  2. 或者这是我应该在 PHP 中处理的事情吗?如果是这样,是否有更优雅的解决方案将所有结果添加到数组中,然后循环返回数组并删除重复项?

想法?

【问题讨论】:

  • 您到底想用
  • 我想只显示具有特定角色的客户并让他们选择。我实际上并不需要在这个特定实例中提取角色名称。

标签: php mysql relationship


【解决方案1】:

如果你想同时显示这两个角色,那么你的查询是OK

MySQL 不支持数组数据类型,因此您应该使用具有重复客户端名称的结果集在PHP 端填充关联数组。

如果您只需要显示具有任一角色的客户,请使用以下查询:

SELECT  c.*
FROM    client c
WHERE   c.clientid IN
        (
        SELECT  roleid
        FROM    client_role_link crl
        WHERE   crl.roleid IN (1, 2)
        )

这将为每个客户返回一条记录,但不会显示任何角色。

第三种方式会在服务器端内爆角色名称:

SELECT  c.*, GROUP_CONCAT(role_name SEPARATOR ';') AS roles
FROM    client c
LEFT JOIN
        client_role_link crl
ON      crl.clientid = c.clientid
        AND crl.roleid IN (1, 2)
LEFT JOIN
        role r
ON      r.roleid = crl.roleid
GROUP BY
        c.id

并在PHP 一侧分解它们,但要确保角色名称不会与分隔符混合。

【讨论】:

  • 我认为第一个示例更符合我正在寻找的内容,但我对“IN”不太熟悉,所以我必须查一下。我假设您只是针对生成的数据集运行 SQL?是的,我知道 MySQL 没有数组,我正在使用 mysqli 和 fetch_assoc() 方法将我的数据从结果集中获取到 PHP 数组中。我只是不想循环返回生成的数组并删除重复项!
【解决方案2】:

您可以使用mysql_fetch_assoc() 将它们恢复为数组形式。然后你可能会有类似 未经测试的代码,但可能会工作

$sql = "SELECT client.id, client.client_name, role.role_name FROM client LEFT JOIN client_role_link ON client_role_link.clientid=client.clientid LEFT JOIN role ON client_role_link.roleid=role.roleid WHERE (role.roleid='1' OR role.roleid='2')";
$result = mysql_query($sql);
$res = array();
while ($row = mysql_fetch_assoc($result)) {
    $res[$row['id']]['roles'][] = $row['role_name'];
    $res[$row['id']]['client_name'] = $row['client_name']; //you'll be overwriting each iteration probably a better way
}

【讨论】:

  • 这部分是我试图避免的,但比我想出的解决方案要干净得多。
猜你喜欢
  • 1970-01-01
  • 2021-12-05
  • 2018-12-12
  • 1970-01-01
  • 1970-01-01
  • 2012-12-20
  • 1970-01-01
  • 2020-10-30
  • 2016-01-19
相关资源
最近更新 更多