【问题标题】:How do you display data from multiple entries in a mysql table that are JOINED with another via a single value match?如何显示来自 mysql 表中多个条目的数据,这些条目通过单个值匹配与另一个表连接?
【发布时间】:2016-09-14 05:08:29
【问题描述】:

我需要从一对 MySQL 表中选择并显示信息,但语法不知道。具体来说,我需要将 cwd_user 表中的数据与 cwd_user.id == cwd_user_attribute.user_id 字段上的 cwd_user_attribute 表中的数据相结合,但我还需要在一行中显示 cwd_user_attribute 表中多个条目的值。后者让我难以捉摸。以下是血淋淋的细节:

给定两个表:

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 是团队、经理和/或注释。输出看起来像这样:

+-----------------------+---------+-----------------------+-------------------------------------------------------------------+
| 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 |
+-----------------------+---------+-----------------------+-------------------------------------------------------------------+

【问题讨论】:

  • 听起来您想要一个 PIVOT 表的变体,您可以在其中选择 user_nameattribute_nameattribute_value。每个user_name 显然会出现多次(每个属性一次),但是您需要 PIVOT 将每个属性转换为一列。不幸的是,我的经验在于 SQL Server,但我认为这应该会给您一些指导。我很抱歉,我无法提供更多帮助。 示例: stratosprovatopoulos.com/wp-content/uploads/2013/08/pivot.png(其中 item_type 是您的属性名称,item_amount 是您的属性值)

标签: mysql atlassian-crowd


【解决方案1】:

您可以使用带有属性表的附加LEFT JOIN 来实现该结果。然后使用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

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

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

注意:我删除了与目录表的连接,因为您似乎没有使用它。如果需要过滤,请重新添加。

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

【讨论】:

    猜你喜欢
    • 2015-04-16
    • 2019-06-22
    • 1970-01-01
    • 2015-08-05
    • 1970-01-01
    • 1970-01-01
    • 2021-10-31
    • 2021-11-06
    • 1970-01-01
    相关资源
    最近更新 更多