一对多链接表导致返回重复行

发布于 2024-08-20 15:19:29 字数 888 浏览 4 评论 0原文

到目前为止我所看到的一切都是关于自动删除数据库中的重复条目。我想在开始时强调数据库中没有重复数据。首先我要说的是,我仍然在学习 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 循环来循环结果并将它们输出到

我明白为什么我的查询返回两行,这是有道理的。因此,这里出现了两个问题:

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

想法?

Everything I've seen so far is about removing duplicate entries in a database automatically. I want to stress at the beginning of this that there is no duplicate data in the database. I'll also start with the fact that I'm very much still learning about RDBMS design, normalization, relationships, and, most of all, SQL!

I have a table of clients, with a clientid (PK) and a client_name. I have a table of roles, with a roleid (PK) and a role_name. Any client can have multiple roles associated with it. So I created a client_role_link table, with clientid and roleid as the two fields. Then I run this:

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')

So let's say I have a client that has two roles associated with it (roles '1' and '2'). This query returns two rows, one for each role. When I get these results back I'm using a while loop to cycle through the results and output them into a <select> list. It's then causing two <option>'s with the same client listed.

I understand why my query is returning two rows, it makes sense. So here comes the two fold question:

  1. Is there a better database/table design that I should be using, or a more optimized query?
  2. Or is this something I should handle in the PHP? If so, is there a more elegant solution that adding all the results into an array, then looping back through the array and removing duplicates?

Thoughts?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

〆凄凉。 2024-08-27 15:19:29

如果您想显示这两个角色,那么您的查询就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 端内爆它们,但要确保角色名称不会与分隔符混合。

If you want to show both roles, then your query is OK.

MySQL does not support array datatypes, so you should fill an associative array on the PHP side using the resultset with the duplicate client names.

If you just need to show clients having either of the roles, use this query:

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

This will return one record per client but won't show any roles.

The third way would implode the role names on the server side:

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

and explode them on PHP side, but make sure role names won't mix with the separator.

往日情怀 2024-08-27 15:19:29

您可以使用 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
}

You could use mysql_fetch_assoc() to get them back in array form. Then you could have something like code untested, but may work:

$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
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文