Всем доброго времени суток!
Друзья, подскажите пожалуйста, у меня есть сниппет, вы его можете видет чуть ниже, мне необходимо чтобы он выводил ноды одного типа не в порядке убывания и возрастания (ORDER BY n.created ASC или DESC), а
<?php
$tag = 'Телефоны'; // Настраиваем нужный тег. Если нужен вывод материалов по нескольким терминам, то вместо этого кода пишем следующий:
//$tags = "'термин1','термин2','термин3'";
$type = "image";
$count = 9; // Максимальное количество выводимых нод.
$result = db_query_range(db_prefix_tables("SELECT n.nid, n.title
FROM {node} n
INNER JOIN {term_node} tn ON n.nid = tn.nid
INNER JOIN {term_data} td ON tn.tid = td.tid
WHERE td.name = '%s' AND
n.status = 1
ORDER BY n.created DESC"),$tag,0,$count);
while ($node = db_fetch_object($result)) {
$items[] = node_view(node_load(array('nid' => $node->nid)), $teaser = FALSE, $page = TRUE, $links = FALSE) ;
}
if (isset($items) && is_array($items) && count($items) > 0) {
foreach ($items as $item){
$output .= "
"; }
}
print $output;
?>
случайным образом, чтобы при обновлении страницы определенного товара, похожие товары менялись в отдельном блоке случайным образом. Я нашел подобный сниппет,
<?php
$gallery_name='Телефоны';
$term = taxonomy_get_term_by_name($gallery_name);
$tid = $term[0]->tid;
$thumbs = 9;
$images_arr = (image_get_random($count = $thumbs, $tid));
foreach ($images_arr as $images){
print l(image_display($images, 'thumbnail'),'node/'.$images->nid, array('html'=>TRUE));
}
?>
но он выводит случайным образом только картинки, данный сниппет хорошо будет подходить для фотогаллереи, нежели для вывода товаров определенного типа. Обращаюсь к вам за помощью, т.к. в программировании не очень силен.
Комментарии
Если у вас в таблице строчек 50-100 то подойдет простая конструкция
SELECT COLUMN FROM table1 ORDER BY RAND()
Но а если у вас допустим строчек 10000... то такая конструкция будет тормозить, грузить базу и делать неприятные вещи. Привел ее для примера
Чтобы получить случайное число в ордер бай проделаем следующие шаги
1)
SELECT COUNT(*) AS counter FROM quotes
получили общее количество записей в таблице
2) генерируем случайное число между 0 и counter-1 (естественно занесите результат скуль запроса выше в меременную я назвал ее $counter)
<?php$var=rand(0, $counter-1);?>
3)
SELECT COLUMN FROM table1 LIMIT $var, 1
Да это конечно два запроса... но как показывает практика они гораздо быстрее одного первого
Извиняюсь за неполный ответ. Конструкция приведенная выше даст вам всего одну случайную строку. Если же надо несколько то надо писать что то вроде
<?phpSELECT tab FROM table 1 WHERE id IN ($idlist)?>
где $idlist это нужно количество случайно сгенерированых чисел разделенных запятыми
Спасибо большое Вам за помощь NX-74205, все сделал, все работает! Остановился на первом варианте, т.к. в базе данных 67 таблиц.
не в количестве таблиц дело а в количестве строк конкретной таблице из которой производиться выборка. первый вариант самый медленный
Мдааа, у меня в одной только таблице 14000 записей.
Значит такая схема никуда не годится? (Первый вариант, где я заменил ORDER BY n.created DESC на ORDER BY RAND())
<?php
$tag = 'Телефоны'; // Настраиваем нужный тег. Если нужен вывод материалов по нескольким терминам, то вместо этого кода пишем следующий:
//$tags = "'термин1','термин2','термин3'";
$type = "image";
$count = 9; // Максимальное количество выводимых нод.
$result = db_query_range(db_prefix_tables("SELECT n.nid, n.title
FROM {node} n
INNER JOIN {term_node} tn ON n.nid = tn.nid
INNER JOIN {term_data} td ON tn.tid = td.tid
WHERE td.name = '%s' AND
n.status = 1
ORDER BY RAND()"),$tag,0,$count);
while ($node = db_fetch_object($result)) {
$items[] = node_view(node_load(array('nid' => $node->nid)), $teaser = FALSE, $page = TRUE, $links = FALSE) ;
}
if (isset($items) && is_array($items) && count($items) > 0) {
foreach ($items as $item){
$output .= "
"; }
}
print $output;
?>
очень медленно по сравнению со вторым вариантом. не оптимально вобщем
Не совсем практично, т.к. в таблице могут отсутствовать строки с нужным id, как следствие их удаления...
да точно. завтра подумаю как их исключить.
Друзья, помогите пожалуйста доработать данный сниппет,
<?php
$tag = 'Телефоны'; // Настраиваем нужный тег. Если нужен вывод материалов по нескольким терминам, то вместо этого кода пишем следующий:
//$tags = "'термин1','термин2','термин3'";
$type = "image";
$count = 9; // Максимальное количество выводимых нод.
$result = db_query_range(db_prefix_tables("SELECT n.nid, n.title
FROM {node} n
INNER JOIN {term_node} tn ON n.nid = tn.nid
INNER JOIN {term_data} td ON tn.tid = td.tid
WHERE td.name = '%s' AND
n.status = 1
ORDER BY RAND()"),$tag,0,$count);
while ($node = db_fetch_object($result)) {
$items[] = node_view(node_load(array('nid' => $node->nid)), $teaser = FALSE, $page = TRUE, $links = FALSE) ;
}
if (isset($items) && is_array($items) && count($items) > 0) {
foreach ($items as $item){
$output .= "
"; }
}
print $output;
?>
а то уже вторую неделю пытаюсь решить проблему сам и все никак
Нужно лишь немного изменить вышеуказанный код, где в конечном итоге должно получится вместо одного запроса - ORDER BY RAND(), два запроса. Код полностью исправный и работает на ура, но один запрос не есть хорошо для бд, где таблицы имеют по 14000-15000 записей.
как то так чтоли
<?php
$tag = 'Телефоны'; // Настраиваем нужный тег. Если нужен вывод материалов по нескольким терминам, то вместо этого кода пишем следующий:
//$tags = "'термин1','термин2','термин3'";
$type = "image";
$count = 9; // Максимальное количество выводимых нод.
$cc=db_result(db_query("SELECT COUNT(*) FROM node"));
for ($varI=1;$varI<=9;$varI++)
{
$rnd=rand(0, $cc-1);
$rnd1="$rind1+$rnd,";
}
$result = db_query_range(db_prefix_tables("SELECT n.nid, n.title
FROM {node} n
INNER JOIN {term_node} tn ON n.nid = tn.nid
INNER JOIN {term_data} td ON tn.tid = td.tid
WHERE td.name = '%s' AND
n.status = 1 AND
n.nid IN ($rnd1)"),$tag,0,$count);
while (
$node = db_fetch_object($result)) {$items[] = node_view(node_load(array('nid' => $node->nid)), $teaser = FALSE, $page = TRUE, $links = FALSE) ;
}
if (isset($items) && is_array($items) && count($items) > 0) {
foreach ($items as $item){
$output .= "<div class='setka'>". $item . "</div>"; }
}
print $output;
?>
p.s написал наспех. непроверял, должно работать впринципе
попробовал Ваш код, ошибку в блоке вот такую выводит,
user warning: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ') LIMIT 0, 9' at line 7 query: SELECT n.nid, n.title FROM node n INNER JOIN term_node tn ON n.nid = tn.nid INNER JOIN term_data td ON tn.tid = td.tid WHERE td.name = 'Телефоны' AND n.status = 1 AND n.nid IN (+9732,) LIMIT 0, 9 in Z:\home\localhost\www\magazin\includes\common.inc(1699) : eval()'d code on line 18.
Только что написал наспех.
Предыдущий вариант, мне не нравится, тем что там постоянно дергает БД по не скольку раз.
Написал вот свой вариант, кошерный)))
1.Пишем в крон.
<?php
$type_node="photoalbum"; // тут пишем машинное имя ноды
$sql=db_query("SELECT node.nid FROM node WHERE node.type = '%s' ORDER BY node.nid DESC LIMIT 0, 30", $type_node);
while ($node_nid = db_fetch_object($sql)) {
$nid[]=$node_nid->nid;
}
variable_set("random", $nid);
unset($nid);
?>
Тут мы узнаем номера интересующих нам нод и заносим в постоянные переменные.
Этот
<?phpLIMIT 0 , 30?>
участок кода, можно впринципе удалить. Но если будет 1000 нод, то будет проблема. А так мы ограничиваем колличество нод и уменьшаем и так излишнею нагрузку на БД.2.Пишем в блок с фильтром PHP в скобках <?php ... ?>
<?php
$nid=variable_get("random",1);
$max=count($nid)-1;
$number=5; //количество выводимых нод
for ($i=-1; $i<=$number; $i++){
$node=node_load($nid[rand(0,$max)]);
$output.=node_view($node, $teaser = true, $page = FALSE, $links = TRUE);
}
print
$output;?>
Вуаля и все работает.
Можно конечно без крона обойтись.
Вот вариант без крона.
<?php
$max=count($nid)-1;
$type_node
="photoalbum"; // тут пишем машинное имя ноды$sql=db_query("SELECT node.nid FROM node WHERE node.type = '%s' ORDER BY node.nid DESC LIMIT 0, 30", $type_node);
while ($node_nid = db_fetch_object($sql)) {
$nid[]=$node_nid->nid;
}
$number=5; //количество выводимых нод
for ($i=-1; $i<=$number; $i++){
$node=node_load($nid[rand(0,$max)]);
$output.=node_view($node, $teaser = true, $page = FALSE, $links = TRUE);
}
print $output;
?>
Второй вариант конечно легче. Но нагрузка на БД возрастает прилично. Каждый пользователь будет дергать БД лишний раз. Фигня конечно если их 10. А если их 1000 уже? 1000 лишних запросов получить не хочется.
Поэтому нужно в крон поместить кусок кода, который записывал бы номера нод.
Конечно в таком варианте, есть один минус. Если крон стоит раз в сутки выполнять, то в рандомные ноды, созданная нода попадет только через сутки. Что может конечно и плохо.
В общем тебе решать.
как именно писать в крон, поищи на форуме. уже говорилось.
Спасибо большое iHappy!
Буду пробовать, а что касается твоего второго варианта и моего упрощенного, где сортировка <?php ORDER BY RAND()?>, то можно при использовании этих простых сниппетов допустим просто включить кеш на час, ну или более, чтобы уменьшить нагрузку на сайт и сервер и на этом остановиться, побочных эффектов не будет?
Посещаемость будущего проекта будет 5000 и более в сутки, поэтому сейчас нужно настроить исходный код так, чтобы проблем и зависаний не было.
Я вообще бы не рекомендовал использовать "Вывод рандомной ноды".
лишняя нагрузка на БД, функционала несет мало, толку еще меньше.
Пользы ноль. А проблемы реальные могут при большой посещаемости.
Конечно можно организовать модулем данную фигню и настроить при нагрузке, чтобы выключался.
Вариант iHappy содержит такую же ошибку, о которой я писал ранее в этом топике:
Сниппет, который мне помог настроить
очень подходящий, но блин, не знаю почему, он не работает
iHappy, не мог бы его посмотреть, нет ли в нем ошибки?
Что касается дергатни бд, то на этот случай я думаю установить параметры кеша. А на счет крона, то здесь мне к сож. нужно постоянное обновление нод, максимум 1-2 часа задержки, и то, это за счет жизни кеша.
Удачи.
Результаты запросов к БД не кешируются
Спасибо за поправку, теперь знаю!
Нет в ремени, поэтому вкратце
1) запрос - выводим nid всех нодов которые нужно рандоматизировать (соответственно типу, термину, статусу), вормируем массив из nid
2) используем фукцию http://php.net/manual/en/function.array-rand.php
3) получившийся массив обходим в цикле, загружая через node_load ноды, или через один запрос вытаскиваем нужные поля
Странные строки:
$rnd1="$rind1+$rnd,";
почему бы не
$rnd1 .= ', '.rand(0, $cc-1);
К тому же переменная $rind1 нигде не определяется.Я тебе дал рабочий вариант без крона. А тот вариант, мне чуточку с SQL не понятно там.
пусть сам автор отвечает.
По теме у меня такой вариант:
По крону делаем рандомную выборку с помощью SQL. Количество элементов в выборке на порядок больше чем нужно, например если нужно выводить 6, то делаем выборку 60-ти элементов. Затем формируем 10 блоков и сохраняем результат в кэш. Затем, выводит по порядку или рандомно эти блоки пользователю. И так до следующего запуска крона. Плюсы - нагрузка на базу только во время запуска крона, блоки могут закэшированы стандартными средствами друпал; минусы - показываемые пользователю ноды будут повторяться.
Можно вариант развить дальше, но общая идея, думаю, понятна.
Во-первых, никто не учитывает, что некоторые ноды могут быть удалены, поэтому будут битые "nid". А также необязательно привязываться к крону. Без крона примерно так:
$time_cache = 300;
$cached = cache_get('block:node_random', 'cache_block');
$now = time();
$expire = $cached ? $cached->expire : 0;
if ($expire > $now) {
return $cached->data;
}
else {
//делаем вычисления
cache_set('block:node_random', $output, 'cache_block', time() + $time_cache);
return $output;
}
Интересное рассуждение. У меня на сайте кешируются практически все выборки, блоки и т.д. и т.п.
Вы понимаете о чём я, через cache_set() закешируется что угодно, без него - нет
Не знаю почему, прописал Ваш вариант, такая же ерунда,
user warning: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ' 9523, 11744, 10627, 12866, 4613, 10524, 1849, 3528, 3187) LIMIT 0, 9' at line 7 query: SELECT n.nid, n.title FROM node n INNER JOIN term_node tn ON n.nid = tn.nid INNER JOIN term_data td ON tn.tid = td.tid WHERE td.name = 'Телефоны' AND n.status = 1 AND n.nid IN (, 9523, 11744, 10627, 12866, 4613, 10524, 1849, 3528, 3187) LIMIT 0, 9 in Z:\home\localhost\www\magazin\includes\common.inc(1699) : eval()'d code on line 17.
в чем здесь может быть ошибка? По ходу явно какой-то баг с соединением с бд.
Запятая после скобки лишняя...
Значит это дело в этом запросе, где запятая в одинарных ковычках <?php $rnd1 .= ', '.rand(0, $cc-1); ?>,
а в этом запросе
{$rnd=rand(0, $cc-1);
$rnd1="$rind1+$rnd,";},
предложенном ранее, похожая ошибка,
user warning: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ') LIMIT 0, 9' at line 7 query: SELECT n.nid, n.title FROM node n INNER JOIN term_node tn ON n.nid = tn.nid INNER JOIN term_data td ON tn.tid = td.tid WHERE td.name = 'Телефоны' AND n.status = 1 AND n.nid IN (+9732,) LIMIT 0, 9 in Z:\home\localhost\www\magazin\includes\common.inc(1699) : eval()'d code on line 18.
блин, во задача, по сути простая зараза, но нерешаемая,
Значит что надо делать Drupal-Way, db_placeholders() придумана не просто так и нафига db_prefix_tables()?
Ребят, а такие чудеса,
1.
user warning: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ' 9523, 11744, 10627, 12866, 4613, 10524, 1849, 3528, 3187) LIMIT 0, 9' at line 7 query: SELECT n.nid, n.title FROM node n INNER JOIN term_node tn ON n.nid = tn.nid INNER JOIN term_data td ON tn.tid = td.tid WHERE td.name = 'Телефоны' AND n.status = 1 AND n.nid IN (, 9523, 11744, 10627, 12866, 4613, 10524, 1849, 3528, 3187) LIMIT 0, 9 in Z:\home\localhost\www\magazin\includes\common.inc(1699) : eval()'d code on line 17.
2.
user warning: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ') LIMIT 0, 9' at line 7 query: SELECT n.nid, n.title FROM node n INNER JOIN term_node tn ON n.nid = tn.nid INNER JOIN term_data td ON tn.tid = td.tid WHERE td.name = 'Телефоны' AND n.status = 1 AND n.nid IN (+9732,) LIMIT 0, 9 in Z:\home\localhost\www\magazin\includes\common.inc(1699) : eval()'d code on line 18.
могут происходить из-за того, что сайт пока на localhost, ведь уже не первый знающий человек думаю верно помогает,
и сниппет вроде рабочий получается, а результат "error"
Что касается подсказки
, то почитав инфу про http://api.drupal.ru/api/function/db_placeholders, так и не могу разобраться как ее применить в моем случае, т.е. на этом сниппете,<?php
$tag = 'Телефоны'; // Настраиваем нужный тег. Если нужен вывод материалов по нескольким терминам, то вместо этого кода пишем следующий:
//$tags = "'термин1','термин2','термин3'";
$type = "image";
$count = 9; // Максимальное количество выводимых нод.
$cc=db_result(db_query("SELECT COUNT(*) FROM node"));
for ($varI=1;$varI<=9;$varI++)
{
$rnd1 .= ', '.rand(0, $cc-1);
}
$result = db_query_range(db_prefix_tables("SELECT n.nid, n.title
FROM {node} n
INNER JOIN {term_node} tn ON n.nid = tn.nid
INNER JOIN {term_data} td ON tn.tid = td.tid
WHERE td.name = '%s' AND
n.status = 1 AND
n.nid IN ($rnd1)"),$tag,0,$count);
while ($node = db_fetch_object($result)) {
$items[] = node_view(node_load(array('nid' => $node->nid)), $teaser = FALSE, $page = TRUE, $links = FALSE) ;
}
if (isset($items) && is_array($items) && count($items) > 0) {
foreach ($items as $item){
$output .= "
"; }
}
print $output;
?>
Локалхост тут не причём. Проблемы в том, что у вас генерируется некорректный запрос. Вы понимаете где в вашем запросе ошибка?
<?php<?
$tag = 'Телефоны'; // Настраиваем нужный тег. Если нужен вывод материалов по нескольким терминам, то вместо этого кода пишем следующий:
//$tags = "'термин1','термин2','термин3'";
$type = "image";
$count = 9; // Максимальное количество выводимых нод.
$arr = $result = db_query_range('FROM {node} n
INNER JOIN {term_node} tn ON n.nid = tn.nid
INNER JOIN {term_data} td ON tn.tid = td.tid
WHERE td.name = \'%s\' AND
n.status = 1', $tag);
$nidarr = array();
while ($data = db_fetch_object($result)) {
$nid_arr[] = $data->nid;
}
$rand_keys = array_rand($nid_arr, $count);
if (isset($rand_keys) && is_array($rand_keys) && count($rand_keys) > 0) {
foreach ($rand_keys as $nid){
$output .= "<div class='setka'>". node_view(node_load($nid , $teaser = FALSE, $page = TRUE, $links = FALSE) . "</div>"; }
}
print $output;
?>
сейчас вообще вот что выдает,
Parse error: syntax error, unexpected ';' in Z:\home\localhost\www\magazin\includes\common.inc(1699) : eval()'d code on line 21,
по ходу уже видимо ошибка где-то в коде
<?php<?
$tag = 'Телефоны'; // Настраиваем нужный тег. Если нужен вывод материалов по нескольким терминам, то вместо этого кода пишем следующий:
//$tags = "'термин1','термин2','термин3'";
$type = "image";
$count = 9; // Максимальное количество выводимых нод.
$result = db_query_range('FROM {node} n
INNER JOIN {term_node} tn ON n.nid = tn.nid
INNER JOIN {term_data} td ON tn.tid = td.tid
WHERE td.name = \'%s\' AND
n.status = 1', $tag);
$nid_arr = array();
while ($data = db_fetch_object($result)) {
$nid_arr[] = $data->nid;
}
$rand_keys = array_rand($nid_arr, $count);
if (isset($rand_keys) && is_array($rand_keys) && count($rand_keys) > 0) {
foreach ($rand_keys as $nid){
$output .= "<div class='setka'>". node_view(node_load($nid , $teaser = FALSE, $page = TRUE, $links = FALSE) . "</div>";
}
}
print $output;
?>
та же история,
Parse error: syntax error, unexpected ';' in Z:\home\localhost\www\magazin\includes\common.inc(1699) : eval()'d code on line 22
только ошибку выдает на 22 строчке, сначала думал, что это может быть из-за небольшой огрешности, где Вы случайно указали в начале кода <?php<? ?>, а оказалось и без нее тот же error, блин, во математика
в том то и дело, что не понимаю где в запросе ошибка. С одним простым запросом <?php ORDER BY RAND()?> все работает отлично, но это не для моего случая, с двумя запросами непонятно почему, но не работает.
А где может генерироваться некорректный запрос? И как его можно исправить?
странновато как-то что селект без селекта
Ребята, вы бы подучили чуть-чуть SQL и PHP - реально поможет.
Знаю что надо учить SQL и PHP, этим и занимаюсь потихоньку, только в этом случае мне до начала июля нужно с этим сниппетом разобраться, время жмет, я даже готов отблагодарить (200wmr) за корректную донастройку, а затем написать в этот топик причины ошибки и если это дело в сниппете, то выложить работающий вариант сюда для тех, у кого в будущем случатся подобные ситуации.
когда в запросе убираю запятую, то ошибка аналогичная, но без запятых,
user warning: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '5812 7741 1069 734 6689 9900 8788 1632) LIMIT 0, 9' at line 7 query: SELECT n.nid, n.title FROM node n INNER JOIN term_node tn ON n.nid = tn.nid INNER JOIN term_data td ON tn.tid = td.tid WHERE td.name = 'Телефоны' AND n.status = 1 AND n.nid IN ( 11482 5812 7741 1069 734 6689 9900 8788 1632) LIMIT 0, 9 in Z:\home\localhost\www\magazin\includes\common.inc(1699) : eval()'d code on line 17.
поэтому не в этом беда
лучше б спереди запятую убрал
<?php
$tag = 'Телефоны'; // Настраиваем нужный тег. Если нужен вывод материалов по нескольким терминам, то вместо этого кода пишем следующий:
//$tags = "'термин1','термин2','термин3'";
$type = "image";
$count = 9; // Максимальное количество выводимых нод. $result = db_query_range('SELECT n.nid FROM {node} n
INNER JOIN {term_node} tn ON n.nid = tn.nid
INNER JOIN {term_data} td ON tn.tid = td.tid
WHERE td.name = \'%s\' AND
n.status = 1', $tag);
$nid_arr = array();
while ($data = db_fetch_object($result)) {
$nid_arr[] = $data->nid;
} $rand_keys = array_rand($nid_arr, $count);
if (isset(
$rand_keys) && is_array($rand_keys) && count($rand_keys) > 0) {foreach ($rand_keys as $nid){
$output .= "<div class='setka'>". node_view(node_load($nid , $teaser = FALSE, $page = TRUE, $links = FALSE) . "</div>";
}
}
print $output;
?>
Спешил, селект забыл
от Gumk
Parse error: syntax error, unexpected ';' in Z:\home\localhost\www\magazin\includes\common.inc(1699) : eval()'d code on line 22
я пробовал ранее добавлять в Ваш код select, результат чуть выше
становится реально смешно))
Ребят, помогите пожалуйста, настройте этот сниппет, кто поможет и код будет работать, заплачу 200р на яндекс деньги!
<?php
$tag = 'Телефоны'; // Настраиваем нужный тег. Если нужен вывод материалов по нескольким терминам, то вместо этого кода пишем следующий:
//$tags = "'термин1','термин2','термин3'";
$type = "image";
$count = 9; // Максимальное количество выводимых нод.
$result = db_query_range(db_prefix_tables("SELECT n.nid, n.title
FROM {node} n
INNER JOIN {term_node} tn ON n.nid = tn.nid
INNER JOIN {term_data} td ON tn.tid = td.tid
WHERE td.name = '%s' AND
n.status = 1
ORDER BY RAND()"),$tag,0,$count);
while ($node = db_fetch_object($result)) {
$items[] = node_view(node_load(array('nid' => $node->nid)), $teaser = FALSE, $page = TRUE, $links = FALSE) ;
}
if (isset($items) && is_array($items) && count($items) > 0) {
foreach ($items as $item){
$output .= "
"; }
}
print $output;
?>
напомню, нужно вывести в блоке 9 нод определённого типа в случайном порядке (без использования ORDER BY RAND()
Привет, ну как ты, справился сам или помогли?