MYSQL объединяет набор результатов уничтоженных результатов во время IN () в предложении where? - PullRequest
2 голосов
/ 10 января 2011

Сильно отредактировано!

Исходный вопрос был основан на неправильном понимании того, как IN () обрабатывает столбец из набора результатов из объединения.Я думал, что IN (some_join.some_column) будет обрабатывать столбец результатов как список и проходить по каждой строке на месте.Оказывается, это выглядит только в первом ряду.

Итак, адаптированный вопрос: есть ли в MySQL что-нибудь, что может циклически проходить через столбец результатов из объединения из предложения WHERE?

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

Сначала БД

Таблица 1: Персона

+----+------+
| id | name |
+----+------+
|  1 | Bob  |
|  2 | Jill |
+----+------+

Таблица 2: Метка

+-----------+--------+
| person_id | tag_id |
+-----------+--------+
|         1 |      1 |
|         1 |      2 |
|         2 |      2 |
|         2 |      3 |
+-----------+--------+

Красиво и просто.Итак, естественно:

SELECT name, GROUP_CONCAT(tag.tag_id) FROM person LEFT JOIN tag ON person.id = tag.person_id GROUP BY name;
+------+--------------------------+
| name | GROUP_CONCAT(tag.tag_id) |
+------+--------------------------+
| Bob  | 1,2                      |
| Jill | 2,3                      |
+------+--------------------------+

Пока все хорошо.Так что я ищу то, что бы найти только Боба в первом случае и только Джилл во втором - без использования HAVING COUNT (DISTINCT ...), потому что это не работает в более широком запросе (есть отдельные тегиКэш наследования и куча других вещей).

Вот мои оригинальные примеры запросов - основанные на ложной идее, что IN () будет циклически проходить по всем строкам одновременно.

SELECT DISTINCT name FROM person LEFT JOIN tag ON person.id = tag.person_id 
  WHERE ( ( 1 IN (tag.tag_id) ) AND ( 2 IN (tag.tag_id) ) );                            
Empty set (0.00 sec)

SELECT DISTINCT name FROM person LEFT JOIN tag ON person.id = tag.person_id 
  WHERE ( ( 2 IN (tag.tag_id) ) AND ( 3 IN (tag.tag_id) ) );
Empty set (0.00 sec)

Вот мойновая последняя неудачная попытка дать представление о том, к чему я стремлюсь ...

SELECT name, GROUP_CONCAT(tag.tag_id) FROM person LEFT JOIN tag ON person.id = tag.person_id 
  GROUP BY person.id HAVING ( ( 1 IN (GROUP_CONCAT(tag.tag_id) ) ) ) AND ( 2 IN (GROUP_CONCAT(tag.tag_id)) );
Empty set (0.00 sec)

Так что, похоже, он принимает строку GROUP_CONCAT, либо 1,2, либо 2,3, и обрабатывает еекак единое целое, а не список выражений.Есть ли способ превратить сгруппированный столбец в список выражений, который IN () или = ANY () будет обрабатывать как список?

По сути, я пытаюсь сделать цикл IN () итеративно над чем-то, чтонапоминает массив или список динамических выражений, который содержит все строки данных, которые поступают из объединения.

Ответы [ 2 ]

4 голосов
/ 10 января 2011

Подумайте о том, что ваш код делает логически:

( 1 IN (tag.tag_id) ) AND ( 2 IN (tag.tag_id) )

эквивалентно

( 1 = (tag.tag_id) ) AND (2 = (tag.tag_id) )

Нет способа, которым tag.tag_id может удовлетворить оба условия одновременно, поэтомуИ никогда не соответствует действительности.

Похоже, что версия OR, которую вы указали в своем вопросе, действительно нужна:

SELECT DISTINCT name FROM person LEFT JOIN tag ON person.id = tag.person_id 
  WHERE ( ( 1 IN (tag.tag_id) ) OR ( 2 IN (tag.tag_id) ) );   

Используя предложение IN более подходящим образом, вы можете написать это как:

SELECT DISTINCT name FROM person LEFT JOIN tag ON person.id = tag.person_id 
  WHERE tag.tag_id in (1,2);   

Последнее замечание: поскольку вы ссылаетесь на столбец из таблицы LEFT JOINed в предложении WHERE (tag.tag_id), вы действительно заставляете его вести себя как INNER JOIN.Чтобы по-настоящему получить СЛЕДУЮЩЕЕ СОЕДИНЕНИЕ, вам нужно вынести критерии из ГДЕ и вместо этого включить их в условия СОЕДИНЕНИЯ:

SELECT DISTINCT name FROM person LEFT JOIN tag ON person.id = tag.person_id 
  AND tag.tag_id in (1,2);   
0 голосов
/ 10 января 2011
 WHERE ( ( 1 IN (tag.tag_id) ) AND ( 2 IN (tag.tag_id) ) );     

Это никогда не вернет никаких результатов, так как tag.tag_id не может быть 1 и 2 одновременно.

Кроме того, есть ли причина, по которой вы используете 1 IN (blah) вместо blah = 1?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...