2012-04-10 4 views
2

Этот запрос выдает правильный ответ:Объединить эти два MySql запросов

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 исправлять соединение «admin, staff, other» - но я не могу понять, как включить его в основной запрос выше?

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

ответ

2

Вы можете попробовать:

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

Привет, Марко - он не работает? Msgstr "Неизвестный столбец 'user_roles.role_ID' в 'on clause'"? Ответ выше «действительно работает», но по какой-то причине он очень медленный - я пытаюсь заставить вас работать ... – Laurence

+1

@Laurencei Измените его на users_roles.role_id. –

+0

ДА !!!!!!!!!!!!!!!!!! Спасибо вам обоим!!!!!!!!!!!!!!!!!!!!!!!! + rep, если бы я мог !!!!!!!!!!!!! Спасли меня так много головной боли! – Laurence

1

Может быть что-то вроде этого:

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

Я получаю сообщение об ошибке, что «users_roles.short_name» неизвестный столбец. Я изменил свой первоначальный вопрос с помощью таблицы users_roles и таблицы ролей, чтобы уточнить. Каким-то образом мне нужно присоединиться к этим двум таблицам, прежде чем CONCAT произойдет ...? – Laurence

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

Я думаю, что вам не хватает таблицы ролей в предложении from из подзаголовка. – newenglander

+0

@newenglander Как верно! Спасибо, я исправил свой ответ. –

+0

Нет проблем. Мне нравится этот запрос, потому что он предотвращает слишком большой выбор списка. – newenglander

0

Я никогда не хотел бы использовать пользовательские функции по запросам, как ядро ​​базы данных обрабатывает функции, как blackboxes и косяк оптимизировать запросы внутри, поэтому следует избегать их, насколько это возможно. С кросс применить вы получите такой же результат, как intendend: (не проверял все запросы, как я не имеют все объекты, используемые)

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

GROUP_CONCAT - встроенная функция агрегации в MySql. –

Смежные вопросы