Здравствуйте,
помогите правильно написать запрос, на данный момент он выглядит так - <?php$count = db_result(db_query(SELECT COUNT(nid) FROM {term_node} WHERE tid ='$term->tid'));?>
т.е. подсчитывается кол-во нод с выбранным термином, а нужно сделать так чтобы подсчитывалось кол-во нод не с одним термином а с тремя, т.е. у ноды совпадает три выбранных термина
примерно это я представляю так <?php$count = db_result(db_query(SELECT COUNT(nid) FROM {term_node} WHERE tid ='$term->tid' AND tid ='$term2->tid' AND tid ='$term3->tid' ));?>
но это конечно не правильный запрос, помогите разобраться, спасибо ...
Комментарии
IN()
т.е. в таком виде точно сработает?
<?php$count = db_result(db_query(SELECT COUNT(nid) FROM {term_node} WHERE tid IN ('$term->tid','$term2->tid','$term3->tid') ));
?>
Мой вариант:
SELECT COUNT(DISTINCT y.nid) FROM {term_node} y
WHERE y.nid IN
(
SELECT x1.nid AS nid FROM {term_node} x1
WHERE x1.tid = 5 or x1.tid = 10 or x1.tid = 15
GROUP BY x1.nid
HAVING COUNT(x1.nid) > 2
)
- выбрать те у которых tid 5,10,15 имеется.
COUNT(x1.nid) > 2 - т.е. три совпадения чтобы было, т.к. три условия.
'$term->tid' - явно никуда не катит, т.к. в таких кавычках инфа будет передаваться в виде строки, а не свойства объекта.
Воспользуйтесь советом natbampo, если человек использует выражение с having, то ему явно можно доверять
Посмотрел повнимательнее, заметил что строчка совсем какая то странная - SELECT COUNT(nid) FROM {term_node} WHERE tid ='$term->tid'). такое не прошло бы интерпретатор, выложите нормальный код или исправьте этот.
большое спасибо, очень помогли
использование этого запроса возможно только в случаях если у вас крайне небольшое количество данных.
достаточно глянуть explain запроса чтобы понять какой ужас ждет сервер при попытке выолнить его.
правильно эта задача решается вот так.
<?php
db_query( 'SELECT COUNT(n.nid) FROM node n
JOIN term_node tn on tn.nid=n.nid
JOIN term_node tn2 on tn2.nid=n.nid
JOIN term_node tn3 on tn3.nid=n.nid
where tn.tid=%d and tn2.tid=%d and tn3.tid=%d', tid, tid2, tid3);?>
в случае если есть уверенность в целостности таблицы term_node запрос можно оптимизировать еще вот до такого состояния.
<?php
db_query( 'SELECT COUNT(tn.nid) FROM term_node tn
JOIN term_node tn2 on tn2.nid=tn.nid
JOIN term_node tn3 on tn3.nid=tn.nid
where tn.tid=%d and tn2.tid=%d and tn3.tid=%d', tid, tid2, tid3);?>
нельзя. запрос составлен крайне не оптимально, без понимания того как mysql оптимизирует запросы.
Только работать не будет так как зависит от порядка аргументов ... да и три самоджойна тоже не очень оптимально ...
Кстати у запроса с вложением не такой уж плохой explain как все привыкли думать
SELECT COUNT(tn.nid) AS cnt,tn.nid
FROM term_node tn WHERE tn.tid IN (%d, %d, %d)
GROUP BY tn.nid
HAVING COUNT(tn.nid) >2
) AS dv ON n.nid=dv.nid
GROUP BY dv.nid", $tid1, $tid2, $tid3);
блин да вы вообще монстры в sql
Ну чот ж давайте разбираться. Вероятно у меня mysql не кошерный но почему то работает.
не говоря уже о том, что именно этот способ используется в taxonomy модуле.
само джоины тут соврешенно пофигу, потому что используются только поля с инедксами.
в общем случае mysql пройдется только по кешу индексов (которые лежат при верной настсройке mysql в памяти).
вы смотрели? хуже может быть только если бы индексов не было вообще.
using temporary создается лишняя временная таблица. А если обьем выходных данных велик, то и создание ее на диск.
using filesort необходим второй проход по результирующему множеству для выдачи его согласно запросу.
вместо того что в мое случае, пройтись по таблице индекса которая лежит(обычно) в оперативной памяти?
и это я еще не обратил Ваше внимание на обьем анализируемых данных, в моем случае и в случае с субзапросом.
по моему кто то кого то просто не понял.
ну и что бы добить до конца вот - на мой взгляд самый оптимальный вариант
SELECT COUNT(tn.nid) FROM term_node tn
JOIN term_node tn2 on tn2.nid=tn.nid and tn2.tid=10
JOIN term_node tn3 on tn3.nid=tn.nid and tn3.tid=15
where tn.tid=5
Да причем тут быстродействие если ваш запрос дает не правильный результат
-> SELECT tn.nid
-> FROM term_node tn WHERE tn.tid IN (223,18,197)
-> GROUP BY tn.nid
-> HAVING COUNT(tn.nid) >2
-> ) AS dv ON n.nid=dv.nid;
+-----+
| cnt |
+-----+
| 4 |
+-----+
1 row in set (0.00 sec)
-> JOIN term_node tn2 on tn2.nid=tn.nid and tn2.tid=197
-> JOIN term_node tn3 on tn3.nid=tn.nid and tn3.tid=223
-> where tn.tid=18;
+---------------+
| COUNT(tn.nid) |
+---------------+
| 1210 |
+---------------+
1 row in set (0.02 sec)
INNER JOIN term_node tn1 ON n.nid = tn1.nid AND tn1.tid = 1
INNER JOIN term_node tn2 ON n.nid = tn2.nid AND tn2.tid = 2
INNER JOIN term_node tn3 ON n.nid = tn3.nid AND tn3.tid = 3
в моем распоряжении две базы
400 000 нод и 201 000 записей в term_data
128 000 нод и 78 000 term_data
все идет именно так как и нужно.
и четко совпадает с результатами вашего запроса.
Мой запрос может работать неправильно только в двух случаях. Оба случая говрят о том что у вас неверная таблица term_node
Случай первый:
Если в таблице term_node у вас присутствую дублирующие друг друга записи.Да это и видно из самого запроса.
проверьте есть ли у вас для одного и того же nid один и тот же tid два раза.
грубо говоря
nid tid
100 18
100 18
чего в принципе быть не должно, это ограничено индексами.
Случай второй:
либо, как я уже предупреждал, у вас в term_node присутствуют nid которых в таблице node нет
Если вы считаете что случай два это НОРМАЛЬНОЕ поведение, то воспользуйтесь моим первым запросом, с привязкой к таблице node
мой запрос абсолютно верен.
Dеmimurych
Ваш вариант считает ноды имеющие хотя бы один из тегов. Просто вы использовали LEFT JOIN а нужен INNER. См. мой вариант выше.
А так, в верном направлении шли..
Да вы правы, но такая ситуация ситуация возникает если нода поддерживает хранение ревизий, т.е. в принципе правильный запрос наверное будет примерно такого вида
INNER JOIN term_node tn on tn.nid=n.nid AND tn.vid=n.vid AND n.status=1 AND tn.tid=%d
INNER JOIN term_node tn2 on tn2.nid=n.nid AND tn2.vid=n.vid AND tn2.tid=%d
INNER JOIN term_node tn3 on tn3.nid=n.nid AND tn3.vid=n.vid AND tn3.tid=%d", $tid1, $tid2, $tid3)
Вообще-то JOIN - и предполагает INNER JOIN, но конечно лучше писать польностью
olk,
вы правы. Перепутал.