Здраствуйте. Пытаюсь реализовать стену как была раньше в вконтакте, старая именно стена, а не микроблоги. Имеются группы, с которых сообщения отображаются на стене, каждое сообщение имеет свой id. Это сообщение от администратора группы. Мне необходимо чтобы пользователи могли цитировать на стене. Цитирование у меня тоже прописано и работает. Только цитируется таким образом, имеется одно сообщение и если под ним оставить два комментария, тогда из одного сообщения получается два. То есть от администратора группы с двумя комментариями. PHP: $res_group_user = mysql_query("SELECT * FROM `group_users` WHERE `user_id`='$id'"); if(mysql_num_rows($res_group_user)>0){ while($rs_gr = mysql_fetch_assoc($res_group_user)){ $gr_admin = $rs_gr['group_admin']; $gr_id = $rs_gr['group_id']; $info_group = mysql_query("SELECT * FROM `group_name` WHERE `group_id`='$gr_id' and `group_admin`='$gr_admin'"); if(mysql_num_rows($info_group)>0){ while($info_gr = mysql_fetch_assoc($info_group)){ $info_name = $info_gr['group_names']; $avatar_res = mysql_query("SELECT `avatar` FROM `users` WHERE `id`='$gr_admin'"); while($row_avatar = mysql_fetch_assoc($avatar_res)){ if($row_avatar['avatar'] == ""){ $avatar = "images/No-Avatar.png"; } else{ $avatar = $row_avatar['avatar']; } $info_mess = mysql_query("SELECT * FROM `group_messages` WHERE `group_admin`='$gr_admin' and `group_id`='$gr_id' and `user_id`='$id' ORDER BY date DESC "); // вот тут сортировка по дате от администратора группы if(mysql_num_rows($info_mess)>0){ while($rs_info = mysql_fetch_assoc($info_mess)){ $comment_res = mysql_query("SELECT * FROM `group_wall` WHERE message_id='".$rs_info['id']."'"); // это вывод из базы комментариев от пользователей которые цитировали if(mysql_num_rows($comment_res)>0){ while ($rs_comment = mysql_fetch_array($comment_res)){ $info_res = mysql_query("SELECT * FROM users WHERE id='".$rs_comment['user_id']."'"); // вывод данных пользователя которые цитировали while($rs_user = mysql_fetch_array($info_res)){ if($rs_user['avatar'] == ""){ $avatar_user = "images/No-Avatar.png"; } else{ $avatar_user = $rs_user['avatar']; } $stena_group .= "<a href='group_room.php?id=".$id."&group=".$gr_admin."&room=".$gr_id."'>Название группы: <b>" . $info_name . "</a></b> <br/><a href='profile.php?id=".$gr_admin."'>Администратор: <b>" . $rs_info['user_first_name'] . " " . $rs_info['user_last_name'] . "</b></a><br/>Сообщение: " . $rs_info['group_messages'] . "<br/>" . $rs_info['date'] . "<br/> Комментарий от:<br/><img src='".$avatar_user." ' style='width:100;height:120px;'><br/>" . $rs_user['lastname'] . " " . $rs_user['first_name'] . "<br/>" .$rs_comment['message']." <br/><br/>"; if($id != $rs_comment['user_id']){ $stena_group .='<p><a href="javascript:void(0);" onclick="comment( document.getElementById('.$rs_info['id'].').value, '.$rs_info['id'].' );"> Отправить</a> </p> </form><br/><br />'; } } } } else{ $stena_group .= "<a href='group_room.php?id=".$id."&group=".$gr_admin."&room=".$gr_id."'>Название группы: <b>" . $info_name . "</a></b> <br/><a href='profile.php?id=".$gr_admin."'>Администратор: <b>" . $rs_info['user_first_name'] . " " . $rs_info['user_last_name'] . "</b></a><br/>Сообщение: " . $rs_info['group_messages'] . "<br/>" . $rs_info['date'] . "<br/> <form id='submit_wall' > <p><input type='text' name='comment' id='".$rs_info['id']."' value='' style='height:100p' /></p> <p> <input type='hidden' name='messageid' id='".$rs_info['id']."' value='".$rs_info['id']."'></p>"; $stena_group .='<p><a href="javascript:void(0);" onclick="comment( document.getElementById('.$rs_info['id'].').value, '.$rs_info['id'].' );"> Отправить</a> </p> </form><br/><br />'; } } } } } } } } Прикладываю изображение как оно все выглядит Название группы test open и сообщение test - это одно сообщение, а проверка и проверка 2 это два разных комментария, которые должны отобразиться под одним сообщением администратора, то есть под сообщением test. Подскажите, пожалуйста, каким образом сгруппировать и выводить комментарии под каждым сообщением от администратора группы. Сообщений от администратора может быть много и так же каждое должно цитироваться. ID сообщения от администратора группы записывается в отдельную таблицу, за счет чего происходит вывод под каждым сообщением свои комментарии.
для начала я бы рекомендовал избавиться от такого кол-ва вложенных запросов. это просто смерть какая-то...
Часть формы вырезал случайно, но она на сортировку не влияет. --- Добавлено --- Код оптимизирую по окончанию. --- Добавлено --- Убрал один запрос. PHP: $res_group_user = mysql_query("SELECT * FROM `group_users` WHERE `user_id`='$id'"); // поиск пользователя в группе if(mysql_num_rows($res_group_user)>0){ while($rs_gr = mysql_fetch_assoc($res_group_user)){ $gr_admin = $rs_gr['group_admin']; $gr_id = $rs_gr['group_id']; $info_group = mysql_query("SELECT * FROM `group_name` WHERE `group_id`='$gr_id' and `group_admin`='$gr_admin'"); // вывод администратора группы, названия группы, описания, заркрытая или открытая группа и еще разные имеются группы if(mysql_num_rows($info_group)>0){ while($info_gr = mysql_fetch_assoc($info_group)){ $info_name = $info_gr['group_names']; $info_mess = mysql_query("SELECT * FROM `group_messages` WHERE `group_admin`='$gr_admin' and `group_id`='$gr_id' and `user_id`='$id' ORDER BY date DESC"); // вывод сообщения от администратора, именно от администратора, а не тех что еще пользователи писали if(mysql_num_rows($info_mess)>0){ while($rs_info = mysql_fetch_assoc($info_mess)){ $comment_res = mysql_query("SELECT * FROM `group_wall` WHERE message_id='".$rs_info['id']."'"); // вывод комментария от пользователя с группы где он присутствует if(mysql_num_rows($comment_res)>0){ while ($rs_comment = mysql_fetch_array($comment_res)){ $info_res = mysql_query("SELECT * FROM users WHERE id='".$rs_comment['user_id']."' and `id`='$gr_admin'"); // вывод информации о пользователе, об администраторе и названии группы выше выводится while($rs_user = mysql_fetch_array($info_res)){ if($rs_user['avatar'] == ""){ $avatar_user = "images/No-Avatar.png"; } else{ $avatar_user = $rs_user['avatar']; } $stena_group .= "<a href='group_room.php?id=".$id."&group=".$gr_admin."&room=".$gr_id."'>Название группы: <b>" . $info_name . "</a></b> <br/><a href='profile.php?id=".$gr_admin."'>Администратор: <b>" . $rs_info['user_first_name'] . " " . $rs_info['user_last_name'] . "</b></a><br/>Сообщение: " . $rs_info['group_messages'] . "<br/>" . $rs_info['date'] . "<br/> Комментарий от:<br/><img src='".$avatar_user." ' style='width:100;height:120px;'><br/>" . $rs_user['lastname'] . " " . $rs_user['first_name'] . "<br/>" .$rs_comment['message']." "; if($id == $rs_comment['user_id']){ $stena_group .=' <form id="submit_wall" > <p><input type="text" name="comment" id="'.$rs_info['id'].'" value="" style="height:100p" /></p> <p> <input type="hidden" name="messageid" id="'.$rs_info['id'].'" value="'.$rs_info['id'].'"></p><p><a href="javascript:void(0);" onclick="comment( document.getElementById('.$rs_info['id'].').value, '.$rs_info['id'].' );"> Отправить</a> </p> </form><br/><br />'; } } } } else{ $stena_group .= "<a href='group_room.php?id=".$id."&group=".$gr_admin."&room=".$gr_id."'>Название группы: <b>" . $info_name . "</a></b> <br/><a href='profile.php?id=".$gr_admin."'>Администратор: <b>" . $rs_info['user_first_name'] . " " . $rs_info['user_last_name'] . "</b></a><br/>Сообщение: " . $rs_info['group_messages'] . "<br/>" . $rs_info['date'] . "<br/> <form id='submit_wall' > <p><input type='text' name='comment' id='".$rs_info['id']."' value='' style='height:100p' /></p> <p> <input type='hidden' name='messageid' id='".$rs_info['id']."' value='".$rs_info['id']."'></p>"; $stena_group .='<p><a href="javascript:void(0);" onclick="comment( document.getElementById('.$rs_info['id'].').value, '.$rs_info['id'].' );"> Отправить</a> </p> </form><br/><br />'; } } } } } } }
всё же изучи mysql join и перестань собирать данные циклами циклов. сколько у тебя запросов на страницу случается? сто? --- Добавлено --- ну и с mysql_* переходи на mysqli_*
Спасибо за совет, только кто мне советует циклами, кто пишет что join не нужно. Уже сталкивался с работой с несколькими таблицами, изучал join. Только пока вопрос о сортировке и группировке.
ты у попова чтоль совета спросил? ну-ну. давай вместе почитаем: SELECT * FROM `group_users` WHERE `user_id`='$id' - выбор всех данных для пользователя с айдишником. ок. в цикле изучаем что? вот реально ЧТО? у тебя может быть несколько пользователей с одним айдишником? СЕРЬЕЗНО? идентификатор он идентифицирует. в контексте пользователя - он у каждого уникален. ну да ладно. дернул ты цикл, тело выполнилось ровно один раз (потому что я надеюсь у тебя всё же один айдишник не дается многим пользователям), объявил ты переменные: $gr_admin=$rs_gr['group_admin']; $gr_id=$rs_gr['group_id']; ок. тут значит админ группы и идентификатор группы. я не очень себе представляю какая у тебя логика поля "груп_админ" но вполне догадываюсь что "груп_айди" относится к группе пользователя. того самого одного, которого мы получили в единственной итерации результата запроса пользователя по уникальному идентификатору. что мы делаем далее? SELECT * FROM `group_name` WHERE `group_id`='$gr_id' and `group_admin`='$gr_admin' выбираем из таблицы "груп_нейм" группу по... ну ладно по айдишнику, уникальность и всё такое. но по админу-то зачем? вот уже эту пару - пользователь-группа - можно заджойнить и получить один кортеж сразу и с юзером и с группой. ведь группа будет одна. так ведь. УНИКАЛЬНЫЙ ИДЕНТИФИКАТОР ГРУППЫ БУДЕТ УНИКАЛЬНЫМ? или как с пользователем вдруг возможны варианты? опять используем цикл для обработки одной единственной записи группы (ну я надеюсь что единственной). что дальше? SELECT * FROM `group_messages` WHERE `group_admin`='$gr_admin' and `group_id`='$gr_id' and `user_id`='$id' ORDER BY date DESC ну да, опять мы не только по айдишнику группу выбираем но и по админу. и по юзеру. тут архитектура бд только тебе понятна. слово дейт является зарезервированным (ключевым) поэтому если у тебя есть поле с таким незамысловатым названием - имя поля нужно брать в грависы. вернемся к запросу. тут кажется впервые он должен вернуть более одной строки и тогда итерация запроса циклом - вполне подходит. смотрим что же нас ждет дальше. для каждого сообщения (судя по названию таблицы) мы делаем что? та-дааааам: SELECT * FROM `group_wall` WHERE message_id='".$rs_info['id']."' то есть выбираем это сообщение по его идентификатору. что мешает заджойнить с прошлым запросом и получить одну результирующую таблицу слепленную из двух? ну кроме того что тебе кто-то люто посоветовал не юзать джойн и ты решил положить сервер надрачиванием по одной записи сотней запросов? НУ ДА ЛАДНО. нас ведь ждет еще один цикл запросов: SELECT * FROM users WHERE id='".$rs_comment['user_id']."' and `id`='$gr_admin' то есть для каждого коммента мы будем дергать инфу об юзере его написавшем. а если пользователь написал пять комментов? да, это будет пять отдельных запросов на одни и те же данные. заeбок. и как ты можешь догадаться, эту - ТРЕТЬЮ ТАБЛИЦУ - можно заджойнить к первым двум - месаги и вол - и получить одним запросом все нужные тебе данные. с джойнами ты делаешь 1 запрос на группа-имя и 1 запрос на месаги-вол-юзерс. без джойнов ты делаешь 1 на юзера группы, 1 на имя группы, 1 запрос на сообщения, 1 * N запросов на сообщения, 1 * N на юзеров сообщений. 3 + (2*N). минимум 5 против стабильно 2 с джойнами. мне бы хотелось послушать аргументы в пользу отказа от джойна и перехода на вот этот фарш о сотне запросов в данном конкретном случае.
ID у каждого пользователя уникален, переменные разумеется объявлены. Одинаковых быть не может. Админ может создавать разные группы и у каждой группы будет свой id, но id администратора разумеется один, а групп может быть много под разными id. Один админ может иметь группу как 1,2,3,4 и т.д, второй админ группы может так же иметь группу под номером 1,2,3 и так со всеми подряд. Для этого и производится выборка по уникальному id админа и группы Выше на этот вопрос по поводу архитектуры есть ответ. Все уникальное, а по юзеру, чтобы выбрать сообщения с групп на которые подписан пользователь, в каких группах он писал. Не взял в грависы, т.к. собственно и хотел добиться сортировки о чем и писал в первом посте. Уже переписываю код, тут я согласен, еще раз ознакомившись с материалом, что будет проще слепить таблицы и с ними работать. А все остальное пояснил что и как должно работать. Все данные уникальны, нельзя их просто тупо по id дергать и сверять, группы могут иметь разные id и принадлежать одному админу, так же юзер может участвовать в разных группах и писать там сообщения, комментарии.
тебе основы реляционных баз данных надо почитать. есть у тебя список (таблица) пользователей, есть у тебя список (таблица) групп. у каждого пользователя может быть одна первичная группа. связь 1-1. у каждой группы может быть главный администратор (пользователь). связь 1-1. каждый пользователь может состоять в нескольких группах. связь 1-n. при этом по этой же связи можно давать флаг что он не просто пользователь а "младший администратор" группы. то есть возникает еще лишь одна таблица - пользователи в группах. и джойнить первые две через третью вполне удобно.
Можно пожалуйста пример, если не затруднит, да бы проще было вникнуть. PHP: SELECT `group_users.user_id`,`group_name.group_admin` FROM `group_users` INNER JOIN `group_name` ON `group_users.user_id`=`group_name.group_admin`; Пока так пробую в phpmyadmin, ошибку выдает, читаю мануалы. Уже проклинаю того кто мне посоветовал что лучше циклы лепить.
Да, разобрался. Создам отдельную тему, хочу вникнуть что к чему. К этой теме JOIN не подходит, тут другой вопрос был создан. --- Добавлено --- @denis01, на пальцах бы кто накидал на моем примере. В сети читаю, там не совсем все понятно пока что. Хотя бы как и что оно работает. Сейчас тему создам и там все объясню, свои вопросы в разделе новичков.
Ты просто хочешь готовый код? Если нет, то придётся повторять теорию. Потому что ты в ней делаешь ошибку. Может взять задачу по легче, примеры из книг по JOIN поиграться с ними. По другому ты хочешь что кто-то написал изложение по теории, которая уже есть в книгах.
Нет, мне готовый код не нужен, я просто хочу разобраться, чтобы кто-то подсказал и указал на ошибки. А с кодом и так уже играюсь.
я например разобрался как проектировать базы данных, когда мне дали ссылку на "Нормальные формы". Почитай хотябы про первых 3. чтобы въехать в структурированый язык запросов, советую книжку Алана Бьюли, она всего на 300 стр и легко читается Вот когда с этим ознакомишься, будет потом легко.
@machetero, благодарю за совет. Сейчас код выглядит таким образом. PHP: <?php include_once('tpl/head.tpl'); include_once('config.php'); $result_join = mysql_query("SELECT * FROM group_name INNER JOIN group_users ON group_name.group_id=group_users.group_id LEFT JOIN group_messages ON group_name.group_admin=group_messages.group_admin WHERE group_users.user_id='1' GROUP BY group_messages.id ASC") or die(mysql_error()); if(mysql_num_rows($result_join)>0){ while($row = mysql_fetch_array( $result_join)){ $group_stena .= $row['id']; $comment_res = mysql_query("SELECT * FROM `group_wall` WHERE message_id='".$row['id']."' and user_id='1'"); while($row_comment = mysql_fetch_array($comment_res)){ $comment = $row_comment['message']; $comment_data = $row_comment['timedata']; } if(empty($comment)){ $group_stena .= "<a href='group_room.php?id=".$id."&group=".$row['group_admin']."&room=".$row['group_id']."'> Название группы: <b>" . $row['group_names'] . "</a></b> <br/><a href='profile.php?id=".$row['group_admin']."'>Администратор: <b>" . $row['first_name_admin'] . " " . $row['last_name_admin'] . "</b></a><br/>Сообщение: " . $row['group_messages'] . "<br/>" . $row['date'] . "<br/> <form id='submit_wall' > <p><textarea type='text' name='comment' id='".$row['id']."' value='' style='height:100p' /></textarea> <p> <input type='hidden' name='messageid' id='".$row['id']."' value='".$row['id']."'></p> <p><a href='javascript:void(0);' onclick='comment( document.getElementById('".$row['id']."').value, '".$row['id']."' );'> Отправить</a> </p> </form><br/><br />"; } else{ $group_stena .= "<a href='group_room.php?id=".$id."&group=".$row['group_admin']."&room=".$row['group_id']."'> Название группы: <b>" . $row['group_names'] . "</a></b> <br/><a href='profile.php?id=".$row['group_admin']."'>Администратор: <b>" . $row['first_name_admin'] . " " . $row['last_name_admin'] . "</b></a><br/>Сообщение: " . $row['group_messages'] . "<br/>" . $row['date'] . "<br/> Комментарий от:<br/><img src='".$avatar_user." ' style='width:100;height:120px;'><br/>" . $rs_user['last_name'] . " " . $rs_user['first_name'] . "<br/>Сообщение: " .$row_comment['message']." <br/>".$comment_data."<br/><br/> <form id='submit_wall' > <p><textarea type='text' name='comment' id='".$row['id']."' value='' style='height:100p' /></textarea> <p> <input type='hidden' name='messageid' id='".$row['id']."' value='".$row['id']."'></p> <p><a href='javascript:void(0);' onclick='comment( document.getElementById('".$row['id']."').value, '".$row['id']."' );'> Отправить</a> </p> </form><br/><br />"; } } } echo $group_stena; ?> Это тестовый код, только что написал. Будет еще один запрос на вывод аватарки, потом оптимизирую и буду писать адрес аватарки в сообщения или комментарии. Речь не об оптимизации кода. Речь идет о построении диалога. Чтобы было дерево. Есть сообщение с id 1 и есть комментарии которые должны выводиться которые относятся к сообщению id 1. Вот мне необходимо их выводить под каждым сообщением и чтобы было текстовое поле для одного главного сообщения, под всеми комментариями для оставления комментария. Думаю, нужно в сторону условия думать, выводить поле для ввода текста в самом конце коментариев. Каким образом можно организовать такую проверку или сортировку чтобы выводить в самом конце результата?