如何显示 mysql table 中多个条目的数据,这些条目通过单个值匹配与另一个条目连接?

How do you display data from multiple entries in a mysql table that are JOINED with another via a single value match?

我需要 select 并显示来自一对 MySQL table 的信息,但我无法理解语法。具体来说,我需要将 cwd_user table 中的数据与 cwd_user_attribute table 字段中的数据 cwd_user.id == cwd_user_attribute.user_id,但我还需要在一行中显示 cwd_user_attribute table 中多个条目的值。是后者让我望而却步。以下是血淋淋的细节:

给定两个 tables:

mysql (crowd@prod:crowddb)> desc cwd_user;
+---------------------+--------------+------+-----+---------+-------+
| Field               | Type         | Null | Key | Default | Extra |
+---------------------+--------------+------+-----+---------+-------+
| id                  | bigint(20)   | NO   | PRI | NULL    |       |
| user_name           | varchar(255) | NO   |     | NULL    |       |
| active              | char(1)      | NO   | MUL | NULL    |       |
| created_date        | datetime     | NO   |     | NULL    |       |
| updated_date        | datetime     | NO   |     | NULL    |       |
| display_name        | varchar(255) | YES  |     | NULL    |       |
| directory_id        | bigint(20)   | NO   | MUL | NULL    |       |
+---------------------+--------------+------+-----+---------+-------+


mysql (crowd@prod:crowddb)> desc cwd_user_attribute;
+-----------------------+--------------+------+-----+---------+-------+
| Field                 | Type         | Null | Key | Default | Extra |
+-----------------------+--------------+------+-----+---------+-------+
| id                    | bigint(20)   | NO   | PRI | NULL    |       |
| user_id               | bigint(20)   | NO   | MUL | NULL    |       |
| directory_id          | bigint(20)   | NO   | MUL | NULL    |       |
| attribute_name        | varchar(255) | NO   |     | NULL    |       |
| attribute_value       | varchar(255) | YES  |     | NULL    |       |
+-----------------------+--------------+------+-----+---------+-------+

假设 cwd_user_attribute.attribute_name 最多有七个可能的值,我对其中四个感兴趣:lastAuthenticated、Team、Manager Notes。示例:

mysql (crowd@prod:crowddb)> select * from cwd_user_attribute where user_id = (select id from cwd_user where user_name = 'gspinrad');
+---------+---------+--------------+-------------------------+----------------------------------+
| id      | user_id | directory_id | attribute_name          | attribute_value                  |
+---------+---------+--------------+-------------------------+----------------------------------+
|   65788 |   32844 |            1 | invalidPasswordAttempts | 0                                | 
|   65787 |   32844 |            1 | lastAuthenticated       | 1473360428804                    |  
|   65790 |   32844 |            1 | passwordLastChanged     | 1374005378040                    | 
|   65789 |   32844 |            1 | requiresPasswordChange  | false                            | 
| 4292909 |   32844 |            1 | Team                    | Engineering - DevOps             | 
| 4292910 |   32844 |            1 | Manager                 | Matt Karaffa                     |  
| 4292911 |   32844 |            1 | Notes                   | Desk 32:2:11                     | 
+---------+---------+--------------+-------------------------+----------------------------------+
5 rows in set (0.00 sec)

我可以通过以下查询获得按 lastAuthenticated 排序的用户列表:

SELECT cwd_user.user_name, cwd_user.id, cwd_user.display_name, from_unixtime(cwd_user_attribute.attribute_value/1000) as last_login FROM cwd_user JOIN cwd_directory ON cwd_user.directory_id = cwd_directory.id JOIN cwd_user_attribute ON cwd_user.id = cwd_user_attribute.user_id AND cwd_user_attribute.attribute_name='lastAuthenticated' WHERE DATEDIFF((NOW()), (from_unixtime(cwd_user_attribute.attribute_value/1000))) > 90 and cwd_user.active='T' order by last_login limit 4;

结果:

+-----------------------+---------+-----------------------+---------------------+
| user_name             | id      | display_name          | last_login |
+-----------------------+---------+-----------------------+---------------------+
| jenkins-administrator | 1605636 | Jenkins Administrator | 2011-10-27 17:28:05 |
| sonar-administrator   | 1605635 | Sonar Administrator   | 2012-02-06 15:59:59 |
| jfelix                | 1605690 | Joey Felix            | 2012-02-06 19:15:15 |
| kbitters              | 3178497 | Kitty Bitters         | 2013-09-03 10:09:59 |

我需要在输出中添加的是 cwd_user_attribute.attribute_value 的值,其中 cwd_user_attribute.attribute_name 是团队、经理、and/or 注释。输出看起来像这样:

+-----------------------+---------+-----------------------+-------------------------------------------------------------------+
| user_name             | id      | display_name          | last_login          | Team          | Manager      |  Notes       |
+-----------------------+---------+-----------------------+-------------------------------------------------------------------+
| jenkins-administrator | 1605636 | Jenkins Administrator | 2011-10-27 17:28:05 | Internal      | Internal     |              | 
| sonar-administrator   | 1605635 | Sonar Administrator   | 2012-02-06 15:59:59 | Internal      | Internal     |              |
| jfelix                | 1605690 | Joey Felix            | 2012-02-06 19:15:15 | Hardware Eng. | Gary Spinrad | Desk 32:1:51 |
| kbitters              | 3178497 | Kitty Bitters         | 2013-09-03 10:09:59 | Software QA   | Matt Karaffa | Desk 32:2:01 |
+-----------------------+---------+-----------------------+-------------------------------------------------------------------+

您可以通过附加 LEFT JOIN 属性 table 来实现该结果。然后使用 GROUP BY 和聚合 CASE 语句来转换结果(行到列)。

SELECT
    cwd_user.user_name,
    cwd_user.id,
    cwd_user.display_name,
    from_unixtime(cwd_user_attribute.attribute_value/1000) as last_login,
    MIN(CASE WHEN attr2.attribute_name = 'TEAM'    THEN attr2.attribute_value END) as Team,
    MIN(CASE WHEN attr2.attribute_name = 'Manager' THEN attr2.attribute_value END) as Manager,
    MIN(CASE WHEN attr2.attribute_name = 'Notes'   THEN attr2.attribute_value END) as Notes
FROM 
    cwd_user 
JOIN 
    cwd_user_attribute ON cwd_user.id = cwd_user_attribute.user_id
                       AND cwd_user_attribute.attribute_name='lastAuthenticated'
LEFT JOIN 
    cwd_user_attribute attr2 ON  cwd_user.id = attr2.user_id
                             AND attr2.attribute_name IN ('Team', 'Manager', 'Notes')
WHERE 
    DATEDIFF((NOW()), (from_unixtime(cwd_user_attribute.attribute_value/1000))) > 90
    AND cwd_user.active = 'T'
GROUP BY 
    cwd_user.id
ORDER BY 
    last_login 
LIMIT 4

使用严格模式,您需要在 GROUP BY 子句中列出所有未聚合的列

GROUP BY 
    cwd_user.user_name,
    cwd_user.id,
    cwd_user.display_name,
    cwd_user_attribute.attribute_value

另一种方法是只使用三个 LEFT JOIN(每个属性名称一个连接):

SELECT
    cwd_user.user_name,
    cwd_user.id,
    cwd_user.display_name,
    from_unixtime(cwd_user_attribute.attribute_value/1000) as last_login,
    attr_team.attribute_value as Team,
    attr_manager.attribute_value as Manager,
    attr_notes.attribute_value as Notes
FROM cwd_user 
JOIN cwd_user_attribute
  ON  cwd_user.id = cwd_user_attribute.user_id
  AND cwd_user_attribute.attribute_name='lastAuthenticated'
LEFT JOIN cwd_user_attribute attr_team
  ON  cwd_user.id = attr2.user_id
  AND attr2.attribute_name = 'Team'
LEFT JOIN cwd_user_attribute attr_manager
  ON  cwd_user.id = attr2.user_id
  AND attr2.attribute_name = 'Manager'
LEFT JOIN cwd_user_attribute attr_notes
  ON  cwd_user.id = attr2.user_id
  AND attr2.attribute_name = 'Notes'
WHERE DATEDIFF((NOW()), (from_unixtime(cwd_user_attribute.attribute_value/1000))) > 90
  and cwd_user.active='T'
order by last_login limit 4

注意:我已经删除了与目录 table 的连接,因为您似乎不使用它。如果您需要它进行过滤,请再次添加它。

注意 2:您经常用于搜索的一些属性(如 lastAuthenticated)应转换为用户中的索引列 table 以提高搜索性能。