SQLinfo.ru - Все о MySQL

Форум пользователей MySQL

Задавайте вопросы, мы ответим

Вы не зашли.

#1 24.05.2008 19:47:12

Petry
Участник
Зарегистрирован: 24.05.2008
Сообщений: 1

Уникальная выборка из таблицы

Подскажите пожалуйста, как сделать запрос, так чтобы значение поля 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

Неактивен

 

#2 25.05.2008 01:37:19

rgbeast
Администратор
MySQL Authorized Developer and DBA
Откуда: Москва
Зарегистрирован: 21.01.2007
Сообщений: 3878

Re: Уникальная выборка из таблицы

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;

Неактивен

 

#3 25.05.2008 07:08:21

EugeneTM
Гуру
Зарегистрирован: 11.04.2008
Сообщений: 89

Re: Уникальная выборка из таблицы

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)

Неактивен

 

#4 25.05.2008 12:45:44

rgbeast
Администратор
MySQL Authorized Developer and DBA
Откуда: Москва
Зарегистрирован: 21.01.2007
Сообщений: 3878

Re: Уникальная выборка из таблицы

Не вполне пофигизм, а скорее желание совместимости. В вопроске топика не конкретизирован алгоритм выбора email, поэтому такой запрос часто появляется в веб-приложениях, хотя он противоречит стандарту SQL. Выполните SET @@sql_mode:='ONLY_FULL_GROUP_BY'; и приведенный запрос будет возвращаться с ошибкой.

Неактивен

 

#5 25.05.2008 17:24:46

EugeneTM
Гуру
Зарегистрирован: 11.04.2008
Сообщений: 89

Re: Уникальная выборка из таблицы

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, то и не надо его получать. Если имеет значение - нужны правила по его выбору.  Иными словами, при тщательной постановке задачи, подобная дискуссия и не возникла бы.

Неактивен

 

#6 25.05.2008 19:45:39

rgbeast
Администратор
MySQL Authorized Developer and DBA
Откуда: Москва
Зарегистрирован: 21.01.2007
Сообщений: 3878

Re: Уникальная выборка из таблицы

На поле id не обратил внимание. На самом деле если несколько полей и некие условия сортировки, то потребуется подзапрос или JOIN.

Для задачи ТС, как я понимаю, лучше всего подойдет GROUP_CONCAT(email) - на выходе будут все email-адреса данного юзера

Неактивен

 

#7 12.06.2008 03:50:12

Игоряныч
Участник
Зарегистрирован: 12.06.2008
Сообщений: 2

Re: Уникальная выборка из таблицы

Прошу прощения, но как чайник из Ваших постов всё-таки не понял как мне поступить.

Есть скрипт, который выбирает из БД последние посты, допустим всего 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)

Неактивен

 

#8 12.06.2008 06:33:45

EugeneTM
Гуру
Зарегистрирован: 11.04.2008
Сообщений: 89

Re: Уникальная выборка из таблицы

Игоряныч написал:

Прошу прощения, но как чайник из Ваших постов всё-таки не понял как мне поступить.

Есть скрипт, который выбирает из БД последние посты, допустим всего 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 запрос расширить без проблем.

Неактивен

 

#9 12.06.2008 14:28:30

Игоряныч
Участник
Зарегистрирован: 12.06.2008
Сообщений: 2

Re: Уникальная выборка из таблицы

EugeneTM, спасибо!
Интересно, что заставило автора "гонять запросы в цикле"? Может, чтобы вывести список из 15 результатов на экран?  Увы скрипт не мой, это плагин к одной из многочисленных CMS. Сомневаюсь, что на данном этапе мои знания PHP и MySQL позволят мне реализовать Ваш совет sad Но постараюсь что-нибудь сделать.

Неактивен

 

Board footer

Работает на PunBB
© Copyright 2002–2008 Rickard Andersson