2016-08-30 5 views
2

Итак, у меня есть две таблицы, одна из которых содержит всех пользователей, а другая - пользователей с соответствующими группами. То, что я пытаюсь сделать, - это получить все идентификаторы пользователей во второй таблице, чтобы получить всю необходимую информацию из первой таблицы. Мое объяснение немного сумбурно, но я думаю, что приведенный ниже код должен быть достаточно ясноИспользование in from group_concat

SELECT 
    * 
FROM 
    USER 
WHERE 
    id IN (
     SELECT 
      group_concat(userid) 
     FROM 
      user_membership 
     WHERE 
      groupid = 45 
    ); 

Однако то, что возвращает пустое множество. Когда я заменяю 'in' на '=', он возвращает одну запись (как и ожидалось). Что не так с моим синтаксисом? Благодарю.

ответ

3

Вам не нужно group_concat() здесь, как это присоединяет каждый userid в столбец строки и вам нужно сравнить каждыйuser.id с одним user_membership.userid значением, а не весь набор. Это операция по переполнению.

Простой выбор будет достаточным. Тем не менее, это, вероятно, будет более эффективным, чтобы переписать запрос с использованием EXISTS:

select * 
from user u 
where exists (
    select 1 
    from user_membership um 
    where u.id = um.userid 
    and groupid = 45 
) 

Если вы действительно настаиваем на предложении IN тогда правильный запрос будет выглядеть:

select * 
from user 
where id in (
    select userid 
    from user_membership 
    where groupid = 45 
) 
+0

Гораздо лучше использовать IN, поскольку существующий запрос занял 2,22 секунды, а в версии - 0,00. Но спасибо. –

+0

Я не уверен, что это правда. Помните, что кеширование играет здесь большую роль. Для сравнения производительности вам нужно будет провести холодные тесты. Вы также можете добавить предложение 'EXPLAIN' в начале, чтобы увидеть план выполнения запроса для каждого из этих запросов. –

1

Вы можете использовать FIND_IN_SET

SELECT 
* 
FROM USER 
WHERE 
FIND_IN_SET(id ,(SELECT group_concat(userid) FROM user_membership WHERE groupid = 45)) 

Вы можете использовать INNER JOIN

SELECT 
    U.* 
FROM USER U 
INNER JOIN user_membership UM ON UM.userid = U.id 
WHERE UM.groupid = 45 

Или вы можете использовать EXISTS, как упоминается в его ответе Kamil G.

0

id - номер, group_concat возвращает строку, содержащую все идентификаторы, разделенные запятой. Я не знаю причины поведения вы испытали, но я полагаю, вы могли бы решить эту проблему так:

SELECT 
    * 
FROM 
    USER 
WHERE 
    (
     SELECT 
      CONCAT(',', CONCAT(group_concat(userid), ',')) 
     FROM 
      user_membership 
     WHERE 
      groupid = 45 
    ) LIKE CONCAT(',', CONCAT(id, ',')); 

Пояснения: мы пишем запятую в начале и в конце внутреннего результата, чтобы позволить LIKE иметь общий оператор. Но ваш запрос может быть оптимизирован, если вы используете EXISTS:

SELECT 
    * 
FROM 
    USER 
WHERE 
    EXISTS (
     SELECT 
      1 
     FROM 
      user_membership 
     WHERE 
      user_membership.groupid = 45 and user_membership.userid = USER.id 
    ); 
+0

Да, я думаю, проблема заключалась в том, что это была строка (которую я не понимал), поскольку ранее я использовал group_concat для извлечения информации в php-скрипт, который я тогда что-то делал. –

+0

@ A.Lau, да, и кажется, что был случай, когда есть один идентификатор пользователя с группой, которую вы ищете, и в этом случае, с = вы получаете идентификатор пользователя. Я показал вам, как вы можете сделать свой код и как упростить/оптимизировать свой код.К сожалению, я оставил group_concat в коде, так что избиратель был прав при голосовании. Тем не менее, я отредактировал ответ, чтобы исправить это. –

0

Выглядит гораздо больше похоже на работу для объединения

SELECT 
    * 
FROM 
    USER u inner join 
    user_membership m on m.userid = u.id 
WHERE 
     m.groupid = 45 
    ; 

Это должно работать намного быстрее, так как запрос может более легко использовать индекс

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