【问题标题】:Combine these two mySQL queries结合这两个 mySQL 查询
【发布时间】:2012-04-22 12:49:34
【问题描述】:

此查询产生正确答案:

SELECT users.*,
        SUM(overtime_list.shift_length) AS overtime_total,
        (SELECT GROUP_CONCAT(users_roles.role_ID) FROM users_roles WHERE users.user_ID = users_roles.user_ID) AS roles
    FROM availability_list
    INNER JOIN users
        ON users.user_ID = availability_list.user_ID
    INNER JOIN stations
        ON users.station_ID = stations.station_ID
    INNER JOIN overtime_list
        ON overtime_list.user_ID = users.user_ID
        AND overtime_list.date >= '$totalovertimedays'
    WHERE availability_list.date = '$date'
    AND availability_list.type = '$type'
    GROUP BY users.user_ID
    ORDER BY overtime_total ASC

输出:

 +----------+---------+----------------------------+------------------+
 |  user_ID | user    |   roles                    |  overtime_total  |
 +----------+---------+----------------------------+------------------+
 |        1 |   Smith |    1,2                     |        12        |
 +----------+---------+----------------------------+------------------+
 |        2 |   Jones |    1,2,3                   |        7         |
 +----------+---------+----------------------------+------------------+

这是想要的结果:

 +----------+---------+----------------------------+------------------+
 |  user_ID | user    |   roles                    |  overtime_total  |
 +----------+---------+----------------------------+------------------+
 |        1 |   Smith |    Admin, Staff            |        12        |
 +----------+---------+----------------------------+------------------+
 |        2 |   Jones |    Admin, Staff, Other     |        7         |
 +----------+---------+----------------------------+------------------+

这是我可以使用的连接,它似乎允许 group_concat 正确连接“管理员、员工、其他” - 但我不知道如何将其合并到上面的主查询中?

SELECT users.user_id, GROUP_CONCAT(roles.short_name  separator ', ') roles
FROM users
JOIN users_roles ON users.user_ID = users_roles.user_ID
JOIN roles ON users_roles.role_ID= users_roles.role_ID
GROUP BY users.user_ID

users_roles 表:

+----------+---------+
|  user_ID | role_ID |
+----------+---------+
|        1 |   1     |
+----------+---------+
|        2 |   1     |
+----------+---------+
|        2 |   2     |
+----------+---------+
|        2 |   3     |
+----------+---------+
|        1 |   3     |
+----------+---------+

角色表:

+----------+------------+
|  role_ID | short_name |
+----------+------------+
|        1 |   Admin    |
+----------+------------+
|        2 |   Super    |
+----------+------------+
|        3 |   Other    |
+----------+------------+

【问题讨论】:

    标签: mysql sql subquery group-concat


    【解决方案1】:

    你可以试试:

    SELECT users.*,
            SUM(overtime_list.shift_length) AS overtime_total,
            (SELECT GROUP_CONCAT(roles.short_name) FROM users_roles 
             INNER JOIN roles ON user_roles.role_ID = roles.role_ID
             WHERE users.user_ID = users_roles.user_ID) AS roles
        FROM availability_list
        INNER JOIN users
            ON users.user_ID = availability_list.user_ID
        INNER JOIN stations
            ON users.station_ID = stations.station_ID
        INNER JOIN overtime_list
            ON overtime_list.user_ID = users.user_ID
            AND overtime_list.date >= '$totalovertimedays'
        WHERE availability_list.date = '$date'
        AND availability_list.type = '$type'
        GROUP BY users.user_ID
        ORDER BY overtime_total ASC
    

    【讨论】:

    • 嗨,Marco - 它不起作用? “'on 子句'中的未知列'user_roles.role_ID'”?上面的答案“确实有效”,但由于某种原因它真的很慢 - 我正在努力让你的工作......
    • @Laurencei 将其更改为 users_roles.role_id。
    • 是的!!!!!!!!!!!!!!!!!!谢谢你们俩!!!!!!!!!!!!!!!!!!!!!!!! +rep 如果可以的话!!!!!!!!!!!!!救了我这么多头痛!
    【解决方案2】:

    添加派生表并将其连接回用户。使用派生表是因为 overtime_list 上的聚合函数,因此数据不会重复。

    SELECT users.*,
        SUM(overtime_list.shift_length) AS overtime_total,
        roles.roles
    FROM availability_list
    INNER JOIN users
        ON users.user_ID = availability_list.user_ID
    INNER JOIN stations
        ON users.station_ID = stations.station_ID
    INNER JOIN overtime_list
        ON overtime_list.user_ID = users.user_ID
        AND overtime_list.date >= '$totalovertimedays'
    LEFT JOIN
    (
       SELECT users_roles.user_ID, 
              GROUP_CONCAT(roles.short_name  separator ', ') roles
         from users_roles
          INNER JOIN roles ON users_roles.role_ID = roles.role_ID
        group by users_roles.user_ID
    ) roles
      ON users.user_ID = roles.user_ID
    WHERE availability_list.date = '$date'
    AND availability_list.type = '$type'
    GROUP BY users.user_ID
    ORDER BY overtime_total ASC
    

    【讨论】:

    • 我认为您在子选择的 from 子句中缺少角色表。
    • 没问题。我喜欢这个查询,因为它可以防止选择列表变得太长。
    • 谢谢 - 这个工作 - 不幸的是这是一个缓慢的查询(因为我需要做的连接数量)......但至少我现在可以研究它。非常感谢
    • 确保所有连接的列都有最新的索引。
    • 查询从 0.3 秒(在我原来的问题中)到 22 秒,答案在这里。是因为 user_roles 表没有索引吗?作为 user_ID + role_ID 的组合,它是唯一的吗?
    【解决方案3】:

    可能是这样的:

    SELECT users.*,
            SUM(overtime_list.shift_length) AS overtime_total,
            (SELECT GROUP_CONCAT(users_roles.short_name) FROM users_roles WHERE users.user_ID = users_roles.user_ID) AS roles
        FROM availability_list
        INNER JOIN users
            ON users.user_ID = availability_list.user_ID
        INNER JOIN stations
            ON users.station_ID = stations.station_ID
        INNER JOIN overtime_list
            ON overtime_list.user_ID = users.user_ID
            AND overtime_list.date >= '$totalovertimedays'
        WHERE availability_list.date = '$date'
        AND availability_list.type = '$type'
        GROUP BY users.user_ID
        ORDER BY overtime_total ASC
    

    【讨论】:

    • 我得到一个错误,“users_roles.short_name”是一个未知的列。我已经用 users_roles 表和角色表编辑了我的原始问题以澄清。不知何故,我需要在 CONCAT 发生之前加入这两个表......?
    【解决方案4】:

    我从不喜欢在查询中使用用户函数,因为数据库引擎将函数视为黑盒并且无法优化内部查询,因此尽可能避免使用它们。使用交叉应用,您会得到与预期相同的结果:(没有测试所有查询,因为我没有使用所有对象)

    SELECT users.*, 
            SUM(overtime_list.shift_length) AS overtime_total, 
            LEFT(ISNULL(roles.roles, ', '), LEN(ISNULL(roles.roles, ', ')) - 1) as roles 
        FROM availability_list 
        INNER JOIN users 
            ON users.user_ID = availability_list.user_ID 
        CROSS APPLY (
            SELECT short_name + ', '
            FROM roles 
            inner users_roles ON roles.role_id = users_roles.role_ID 
            WHERE users.user_ID = users_roles.user_ID 
            ORDER BY roles.role_id
            FOR XML PATH('')
        ) roles (roles)         
        INNER JOIN stations 
            ON users.station_ID = stations.station_ID 
        INNER JOIN overtime_list 
            ON overtime_list.user_ID = users.user_ID 
            AND overtime_list.date >= '$totalovertimedays' 
        WHERE availability_list.date = '$date' 
        AND availability_list.type = '$type' 
        GROUP BY users.user_ID 
        ORDER BY overtime_total ASC 
    

    【讨论】:

    • GROUP_CONCAT 是 MySql 内置的聚合函数。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-06-10
    • 1970-01-01
    • 1970-01-01
    • 2017-07-03
    • 1970-01-01
    相关资源
    最近更新 更多