Помогите выполнить запрос к базе.

Главные вкладки

Аватар пользователя mNigma@drupal.org mNigma@drupal.org 23 ноября 2012 в 14:05

Добрый день!
Не оч глубока знаю mysql, помогите, пожалуйста, с запросом. Голову сломал.

таблица term_node
nid vid tid
1    1    14
1    1    26

Нужно выбрать nid у которого tid = 14 И 26.
Мой запрос конечно не работает, т.к. ищет в одной строке два параметра, но вот ка его переписать, не могу разобраться.
SELECT nid FROM {term_node} WHERE (tid =%d and tid =%d) GROUP BY nid

Комментарии

Аватар пользователя mNigma@drupal.org mNigma@drupal.org 23 ноября 2012 в 21:16

alekseidolganov wrote:
SELECT nid FROM {term_node} WHERE (tid =%d OR tid =%d) GROUP BY nid

Так пробовал, не то. Мне нужно одно значение nid у которого есть и один и другой термин. А при этом запросе, выбирает и те nid, у которых только 1 из 2 терминов.

P.S. и так пробовал, но при множественном значении тидов, работает неправильно:
SELECT nid FROM {term_node} WHERE (tid =%d and (SELECT tn.nid FROM {term_node} tn WHERE tn.tid=%d LIMIT 1)) GROUP BY nid

Аватар пользователя sg85 sg85 23 ноября 2012 в 21:36

не уверен что правильно, но должно работать:
SELECT s.nid FROM (SELECT nid, COUNT(nid) cnt FROM {term_node} WHERE tid IN(%d,%d) GROUP BY nid) s WHERE s.cnt = 2;

Аватар пользователя sg85 sg85 24 ноября 2012 в 16:12

Ваш вариант мне нравится, но было бы интересно, если бы ТС проверил оба варианта и отписался какой из них работает быстрее, ибо как показала практика, INNER JOIN при большом числе записей может вызвать тормоза сильнее GROUP BY

Аватар пользователя mNigma@drupal.org mNigma@drupal.org 27 ноября 2012 в 17:02

Спасибо за ответы!
Сделать нужно было срочно, сделал немного по другому двумя запросами. Не стал расписывать, будет все равно непонятно с куска кода.
Сегодня протестировал с предложенными запросами.

"Goodboy" wrote:
db_query('SELECT DISTINCT t.nid FROM {term_node} t INNER JOIN {term_node} t2 ON t.nid=t2.nid WHERE (t.tid =%d) AND (t2.tid=%d)', 14, 26);

Интересное решение Smile я к такому не додумался, но не подошло, т.к. у меня выборка 7 терминов (пока) и прописывать 6 раз INNER JOIN не стал, но можно и так поступить.
"sg85" wrote:
SELECT s.nid FROM (SELECT nid, COUNT(nid) cnt FROM {term_node} WHERE tid IN(%d,%d) GROUP BY nid) s WHERE s.cnt = 2;

Использовал этот вариант, хотя сколько не копал, не могу понять как это работает FROM (SELECT..!

Аватар пользователя sg85 sg85 27 ноября 2012 в 17:54

Это двойная выборка, если в двух словах: сперва делается запрос "SELECT nid, COUNT(nid) cnt FROM {term_node} WHERE tid IN(%d,%d) GROUP BY nid", и уже из её результата делается вторая выборка. Первый запрос не очень тяжелый, хоть и с группировкой, а второй для субд вообще почти незаметен, ибо выборка идет из маленькой таблички в кеше, да еще и сам запрос простейший, т.е. в совокупности в будущем не должно возникнуть проблем с производительностью.

Сам механизм такой: выбираются значения, где tid = 1м ИЛИ 2му входному значению, после чего эти значения группируются и подсчитывается кол-во сгруппированных полей, т.е. если нода принадлежала обоим терминам, то в этом счетчике будет содержатся 2, иначе 1, после этого происходит вторая выборка уже из этих результатов, которая возвращает только те ниды, у которых счетчик в прошлой выборке был 2.

Да, кстати, двойная(а так же тройная и т.д. выборки) отличаются от двух реальных запросов в основном тем, что результат нужно будет возвращать всего 1 раз, собственно, как и запрашивать, что происходит быстрее.