【问题标题】:MYSQL JOIN multiple tables, avoiding duplicate entries on duplicate rowsMYSQL JOIN 多个表,避免重复行上的重复条目
【发布时间】:2018-08-29 13:57:47
【问题描述】:

我想 SELECT JOIN 三个表。 其中两个具有唯一条目,但一个可能有多行用于我的主表中的唯一标识符。 如果表三中有多个条目,我想在我的查询结果中获得多行,但我想只获得不同的值,并且之前的行没有重复。 对于一个简单的示例,它应该如下所示:

表用户:

+----------+-----------+--------------+
| user_id  | user_name | email        |
+----------+-----------+--------------+
| 1        | name1     | one@ex.tld   |
| 2        | name2     | two@ex.tld   |
| 3        | name3     | three@ex.tld |
+----------+-----------+--------------+

表信息:

+----------+---------+--------+
| info_id  | user_id | info   |
+----------+---------+--------+
| 1        | 1       | text1  |
| 2        | 2       | text2  |
| 3        | 3       | text3  |
+----------+---------+--------+

表地址:

+------------+--------+----------------+
| address_id | user_id| address_field1 |
+------------+--------+----------------+
| 1          | 1      | City A         |
| 2          | 1      | City B         |
| 3          | 2      | City C         |
| 4          | 2      | City D         |
| 5          | 2      | City E         |
| 6          | 3      | City F         |
+------------+--------+----------------+

我的实际查询是: 选择 u.user_name、u.email、i.info、a.address_field1 来自用户你 INNER JOIN info i ON (u.user_id = i.user_id) INNER JOIN 地址 a ON (u.user_id = a.user_id);

^^我尝试了 LEFT JOIN 和 JOIN 也没有成功。

查询结果:

+-----------+--------------+--------+----------------+
| user_name | email        | info   | address_field1 |
+-----------+--------------+--------+----------------+
| name1     | one@ex.tld   | text1  | City A         |
| name1     | one@ex.tld   | text1  | City B         |
| name2     | two@ex.tld   | text2  | City C         |
| name2     | two@ex.tld   | text2  | City D         |
| name2     | two@ex.tld   | text2  | City E         |
| name3     | three@ex.tld | text3  | City F         |
+-----------+--------------+--------+----------------+

我尝试达到的查询结果:

+-----------+--------------+--------+----------------+
| user_name | email        | info   | address_field1 |
+-----------+--------------+--------+----------------+
| name1     | one@ex.tld   | text1  | City A         |
|           |              |        | City B         |
| name2     | two@ex.tld   | text2  | City C         |
|           |              |        | City D         |
|           |              |        | City E         |
| name3     | three@ex.tld | text3  | City F         |
+-----------+--------------+--------+----------------+

我知道这是可能的,但我不知道怎么做,我不确定我应该搜索什么。有人能把我放在正确的位置吗?

【问题讨论】:

  • 不要在 SQL 中这样做。在检索数据的应用或网页中可以更好地解决此类显示问题。
  • 我不会尝试将其用于生产环境或重复显示数据。这是一次性导出已弃用系统的数据集,应通过 API 将其导入新系统。如果用户可以使用多个地址集,则此 API 需要获取的格式。
  • 好的。您正在将所有用户的信息与所有用户的地址交叉加入。单个用户的五个信息和三个地址构成十五个结果行。您的示例不包含每个用户的多个信息。您能否添加一个具有两个信息和两个地址的用户 #4,并向我们展示结果中的样子?
  • 多个条目仅适用于地址集。每个 user_id 的所有其他数据都是唯一的。我决定自定义 API 并将多个地址行转换为查询结果中的列。这样做似乎没有那么广泛。
  • 那么奇怪的数据模型。列info 应该只是用户表中的一列。似乎根本不需要info 表。

标签: mysql join


【解决方案1】:

请随意阅读此SQLFiddle 以进一步测试此查询及其输出!

SELECT u.user_name, u.email, 
GROUP_CONCAT(info) AS info, 
GROUP_CONCAT(address_field1) AS address_field1
FROM user u
INNER JOIN info i ON (u.user_id = i.user_id)
INNER JOIN address a ON (u.user_id = a.user_id)
GROUP BY u.user_name ASC

| user_name |        email |              info |       address_field1 |
|-----------|--------------|-------------------|----------------------|
|     name1 |   one@ex.tld |       text1,text1 |        City A,City B |
|     name2 |   two@ex.tld | text2,text2,text2 | City C,City D,City E |
|     name3 | three@ex.tld |             text3 |               City F |


谢谢!
奥马尔 M.

【讨论】:

  • 感谢您的回答。这就像在单个条目中回顾第三个表的多个条目的魅力。不幸的是,应该处理查询的 API 无法处理这个问题。
【解决方案2】:

我决定自定义 API,并将存储几个地址数据,如下所示:

+-----------+--------------+--------+----------------+----------------+----------------+
| user_name | email        | info   | address_field1 | address_field2 | address_field3 |
+-----------+--------------+--------+----------------+----------------+----------------+
| name1     | one@ex.tld   | text1  | City A         | City B         |                |
| name2     | two@ex.tld   | text2  | City C         | City D         | City E         |
| name3     | three@ex.tld | text3  | City F         |                |                |
+-----------+--------------+--------+----------------+----------------+----------------+

【讨论】:

    【解决方案3】:

    在标准 SQL 中使用 LAG 或 ROW_NUMBER 可以轻松抑制重复数据,但 MySQL 也没有。

    你可以做的是再次查找地址表中的第一个地址:

    select
      case when is_first then user_name end as user_name,
      case when is_first then email end as email,
      case when is_first then info end as info,
      address_field1
    from
    (
      select 
        u.user_name,
        u.email,
        i.info,
        a.address_field1,
        a.address_field1 = (select min(address_field1)
                            from address fa 
                            where fa.user_id = a.user_id) as is_first
      from user u 
      join info i on u.user_id = i.user_id
      join address a on u.user_id = a.user_id
    ) compared
    order by user_name, email, info, address_field1;
    

    【讨论】:

      【解决方案4】:

      GROUP_CONCAT 结合 GROUP BY 或多或少地满足您的需求。
      没有 SEPARATOR 选项的 GROUP_CONCAT 将生成逗号分隔值

      SET SESSION group_concat_max_len = @@max_allowed_packet    
      
      SELECT u.user_name, u.email, i.info, GROUP_CONCAT(address_field1) AS address_field1
      FROM user u
      INNER JOIN info i ON (u.user_id = i.user_id)
      INNER JOIN address a ON (u.user_id = a.user_id)
      GROUP BY u.user_name, u.email, i.info
      

      【讨论】:

      • 感谢您的回答。这就像在单个条目中回顾第三个表的多个条目的魅力。不幸的是,应该处理查询的 API 无法处理这个问题。
      猜你喜欢
      • 2013-01-14
      • 1970-01-01
      • 1970-01-01
      • 2012-08-24
      • 2014-06-17
      • 1970-01-01
      • 1970-01-01
      • 2023-03-22
      相关资源
      最近更新 更多