Задавайте вопросы, мы ответим
Вы не зашли.
Подскажите пожалуйста, как сделать запрос, так чтобы значение поля name выбиралось единожды для каждого значения
Допустим есть:
id | name | email
_______________
1 | 1 | 1@1.1
2 | 1 | qwe@1.1
3 | 1 | tr@3.2
4 | 2 | 24@1
5 | 2 | 232@qw
6 | 3 | 12322@22.2
и в результате запроса было
1 -> 1 | 1 | 1@1.1
2 -> 4 | 2 | 24@1
3 -> 6 | 3 | 12322@22.2
То есть выборка должна содержать по однуму результату для каждого уникального поля name
Неактивен
Неактивен
rgbeast написал:
SELECT id,name,email FROM t GROUP BY name;
Поле email будет принимать произвольное значение из группы с заданным name. Более корректно написать SELECT id,name,MAX(email) FROM t GROUP BY name; или SELECT id,name,GROUP_CONCAT(email) FROM t GROUP BY name;
Абсолютно не корректно. Нет гарантии , что при каких то условиях мы не получим вместо
1 -> 1 | 1 | 1@1.1
следующее значение
1 -> 2 | 1 | 1@1.1
Вылезти на реальных данных вполне может. И будет абсолютно корректным результатом выполнения запроса.
Причина - пофигизм разработчиков MySQL по отношению к GROUP BY. По стандартам в GROUP BY должны быть включены все поля не участвующие в агрегатирующих функциях и участвующие в запросе. Тот же MSSQL этот запрос не пропустил бы.
В данном случае либо из результата запроса должно быть выброшено поле id, либо в постановке оговорены правила выбора поля id, либо нужно привинчивать притянутые за уши правила по выбору id.
Отредактированно EugeneTM (25.05.2008 10:22:04)
Неактивен
Не вполне пофигизм, а скорее желание совместимости. В вопроске топика не конкретизирован алгоритм выбора email, поэтому такой запрос часто появляется в веб-приложениях, хотя он противоречит стандарту SQL. Выполните SET @@sql_mode:='ONLY_FULL_GROUP_BY'; и приведенный запрос будет возвращаться с ошибкой.
Неактивен
rgbeast написал:
Выполните SET @@sql_mode:='ONLY_FULL_GROUP_BY'; и приведенный запрос будет возвращаться с ошибкой.
Упустил. Спасибо.
А что касается нестандартного использования GROUP BY в MySQL, опасное это дело. Особенно у начинающих. Проблема в том, что на тестах оно зачастую прокатывает к сожалению. И ошибки могут быть нечастыми и очень тяжело локализуемыми.
Хорошо если в данном случае поле id не будет больше нигде использоваться. А если будет. Такой результат в принципе реален
2 | 1 | 1@1.1
но ведь для id = 2, e-mail = qwe@1.1
Проблема в постановке в первую очередь. Как уже выше писал, если не имеет значения поле id, то и не надо его получать. Если имеет значение - нужны правила по его выбору. Иными словами, при тщательной постановке задачи, подобная дискуссия и не возникла бы.
Неактивен
На поле id не обратил внимание. На самом деле если несколько полей и некие условия сортировки, то потребуется подзапрос или JOIN.
Для задачи ТС, как я понимаю, лучше всего подойдет GROUP_CONCAT(email) - на выходе будут все email-адреса данного юзера
Неактивен
Прошу прощения, но как чайник из Ваших постов всё-таки не понял как мне поступить.
Есть скрипт, который выбирает из БД последние посты, допустим всего 15 последних ($postlimit = 15).
...
else if($forumname == 'phpBB2')
{
$getposts = $DB->query("SELECT post_id, topic_id, poster_id, post_username FROM ".$tableprefix."posts ".$extraquery." ORDER BY post_id DESC LIMIT $postlimit");
while($post = $DB->fetch_array($getposts))
{
$thread = $DB->query_first("SELECT topic_title FROM ".$tableprefix."topics WHERE topic_id = '".$post['topic_id']."' ");
if($post['post_username'] == NULL)
{
$lastposter = $DB->query_first("SELECT username FROM ".$tableprefix."users WHERE user_id = '".$post['poster_id']."' ");
$post['post_username'] = $lastposter['username'];
}
$thread['topic_title'] = sd_wordwrap($thread['topic_title'], $wordwrap, "<br />", 1);
echo '<a href="' . $sdurl . $forumpath . 'viewtopic.php?p=' . $post['post_id'] . '#' . $post['post_id'] . '">' . $thread['topic_title'] . '</a>
<br />' . $language['posted_by'] . ' ' . $post['post_username'] . '<br /><br />';
}
}
...
Так всё работает, но если несколько постов из одной темы (т.е. у этих записей БД равны значения topic_id), то естественно все они попадают в выборку и видны в списке последних постов. Т.е. может оказаться, что выбираются 15 последних постов из одной темы.
Я же пытаюсь сделать, чтобы из каждой темы был виден только новейший пост, тогда, даже если 15 самых новых постов будут принадлежать одной теме, в выборку попадёт только последний, новейший пост.
Пробовал добавить в первый запрос GROUP BY topic_id - результат не устраивает: выводятся последние посты из последних тем (т.е. у которых больше значение поля topic_id). А если тема старая, но пост в ней новый, то этот пост в выборку не попадает. К тому же в этом случае в формируемом списке получается ссылка на самый первый пост в теме, а не на последний, как должно быть.
Подскажите, пожалуйста, как мне составить запрос или запросы, вижу, что в скрипте их 3?
Спасибо.
Отредактированно Игоряныч (12.06.2008 04:15:21)
Неактивен
Игоряныч написал:
Прошу прощения, но как чайник из Ваших постов всё-таки не понял как мне поступить.
Есть скрипт, который выбирает из БД последние посты, допустим всего 15 последних ($postlimit = 15).
...
else if($forumname == 'phpBB2')
{
$getposts = $DB->query("SELECT post_id, topic_id, poster_id, post_username FROM ".$tableprefix."posts ".$extraquery." ORDER BY post_id DESC LIMIT $postlimit");
while($post = $DB->fetch_array($getposts))
{
$thread = $DB->query_first("SELECT topic_title FROM ".$tableprefix."topics WHERE topic_id = '".$post['topic_id']."' ");
if($post['post_username'] == NULL)
{
$lastposter = $DB->query_first("SELECT username FROM ".$tableprefix."users WHERE user_id = '".$post['poster_id']."' ");
$post['post_username'] = $lastposter['username'];
}
$thread['topic_title'] = sd_wordwrap($thread['topic_title'], $wordwrap, "<br />", 1);
echo '<a href="' . $sdurl . $forumpath . 'viewtopic.php?p=' . $post['post_id'] . '#' . $post['post_id'] . '">' . $thread['topic_title'] . '</a>
<br />' . $language['posted_by'] . ' ' . $post['post_username'] . '<br /><br />';
}
}
...
Спасибо.
Делай что угодно, но не гоняй никогда запросы в цикле.
Что-то вроде
SELECT posts.post_id, posts.topic_id, posts.poster_id, posts.post_username, tcs.topic_title
FROM posts
LEFT JOIN (SELECT topic_id t_id, MAX(post_id) max_id
FROM posts GROUP BY topic_id ORDER BY max_id DESC LIMIT 15) pst
ON pst.t_id = posts.topic_id AND pst.max_id = posts.post_id
LEFT JOIN topics tcs
ON tcs.topic_id = posts.topic_id
WHERE posts.topic_id IS NULL
Про user'ов не понятна структура данных. В принципе по аналогии с topic_title запрос расширить без проблем.
Неактивен
EugeneTM, спасибо!
Интересно, что заставило автора "гонять запросы в цикле"? Может, чтобы вывести список из 15 результатов на экран? Увы скрипт не мой, это плагин к одной из многочисленных CMS. Сомневаюсь, что на данном этапе мои знания PHP и MySQL позволят мне реализовать Ваш совет Но постараюсь что-нибудь сделать.
Неактивен