Вопрос по SQL запросу

12
siv1987
На сайте с 02.04.2009
Offline
427
975

Имеем:

topics

tid - PRIMARY KEY


+-----+
| tid |
+-----+
| 1 |
| 3 |
+-----+

posts

pid - PRIMARY KEY


+-----+----------+
| pid | topic_id |
+-----+----------+
| 1 | 1 |
| 2 | 1 |
| 8 | 3 |
| 19 | 3 |
+-----+----------+

Как одним запросом присоединить к topics записи из posts с наибольшим pid?


+-----+------+
| tid | pid |
+-----+------+
| 1 | 2 |
| 3 | 19 |
+-----+------+
TF-Studio
На сайте с 17.08.2010
Offline
334
#1

Скиньте запрос на создание таблиц, чтобы не теоретизировать.

Всё ещё лучший способ заработка для белых сайтов: GoGetLinks (https://www.gogetlinks.net/?inv=fahbn8).
edogs software
На сайте с 15.12.2005
Offline
775
#2

Если у Вас задача строго такая, как Вы поставили, то достаточно просто

select tid, max(pid) from topics left join posts on topics.tid=posts.topic_id group by topics.tid

Если же у Вас задача выбрать не просто max pid соответствующий топику, а выбрать еще дополнительные данные, то уточните задачу - какие поля выбирать и какая полная структура таблиц.

Разработка крупных и средних проектов. Можно с криптой. Разумные цены. Хорошее качество. Адекватный подход. Продаем lenovo legion в спб, дешевле магазинов, новые, запечатанные. Есть разные. skype: edogssoft
IL
На сайте с 20.04.2007
Offline
435
#3
edogs:
Если же у Вас задача выбрать не просто max pid соответствующий топику, а выбрать еще дополнительные данные

В общем случае - примерно так (сортируем по убыванию, группируем по нужному полю)

SELECT * FROM
(SELECT t.*, p.* from topics t INNER JOIN posts p ON p.topic_id = t.tid
ORDER BY p.topic_id DESC) t
GROUP BY tid
... :) Облачные серверы от RegRu - промокод 3F85-3D10-806D-7224 ( http://levik.info/regru )
edogs software
На сайте с 15.12.2005
Offline
775
#4
ivan-lev:
В общем случае - примерно так (сортируем по убыванию, группируем по нужному полю)
SELECT * FROM
(SELECT t.*, p.* from topics t INNER JOIN posts p ON p.topic_id = t.tid
ORDER BY p.topic_id DESC) t
GROUP BY tid

В Вашем запросе нет ничего говорящего о максимальном pid, поэтому именно для него вложенный вообще не нужен - вполне достаточно

SELECT t.*, p.* from topics t INNER JOIN posts p ON p.topic_id = t.tid

GROUP BY tid ORDER BY p.topic_id DESC

Но если мы правильно поняли Вашу мысль, то Вам нужно присоединить к таблице topics строку из posts с максимальным ID?

Тогда примерно так


select a.*, b.* from topics as a left join posts as b on a.tid=b.topic_id
left join posts as c on b.topic_id=c.topic_id and b.pid<c.pid
where c.topic_id is null group by a.tid order by a.tid desc

p.s.: Последние сообщения пытаетесь выбрать с форума? Вообще принято при постинге в форум проставлять в таблицу тем номер последнего сообщения, тогда такие проблемы пропадают как класс.

IL
На сайте с 20.04.2007
Offline
435
#5
edogs:
В Вашем запросе нет ничего говорящего о максимальном pid

Ай-ай.. конечно же..

Во вложенном запросе сортировать по pid:

ORDER BY p.pid DESC
edogs software
На сайте с 15.12.2005
Offline
775
#6
ivan-lev:
Ай-ай.. конечно же..
Во вложенном запросе сортировать по pid:
ORDER BY p.pid DESC

Вы вероятно полагаете, что в группу которую Вы делаете потом по tid попадает первая найденная строка из posts, поэтому сортировка вложенного запроса по pid выберет в результирующую таблицу строку с максимальным pid? Это ошибочная точка зрения. На самом деле в случае группировки не определено какая именно строка попадет в группу.

Поэтому приходится извращаться по типу запросов, что мы привели последним в предыдущем сообщбении.

IL
На сайте с 20.04.2007
Offline
435
#7
edogs:
Это ошибочная точка зрения. На самом деле в случае группировки не определено какая именно строка попадет в группу.

Первая попавшаяся ;) (а в данном случае - с максимальным pid т.к. мы точно знаем, какая строка будет первой для каждого tid в результате выполнения подзапроса)

edogs software
На сайте с 15.12.2005
Offline
775
#8
ivan-lev:
Первая попавшаяся ;) (а в данном случае - с максимальным pid т.к. мы точно знаем, какая строка будет первой для каждого tid в результате выполнения подзапроса)

Не первая попавшаяся, а случайная попавшаяся:) mysql не определяет порядок выбора представителя группы если он не задан явно агрегирующими функциями.

В большинстве случае на большинстве текущих версий и конфигураций мускула - выборка будет та, которую Вы ожидаете, но не более того. Это даже более опасно, чем полагаться на выборку select * from table ожидая выборки по возрастанию автоинкримента.

siv1987
На сайте с 02.04.2009
Offline
427
#9
edogs:
Если же у Вас задача выбрать не просто max pid соответствующий топику, а выбрать еще дополнительные данные, то уточните задачу - какие поля выбирать и какая полная структура таблиц.

Да, присоединить со всеми остальными полями, не до конца наверное выразился. Поля и структура думаю особого значения не имеет, так как основная связь это t.tid=p.topic_id, остальное простые данные.


Create Table: CREATE TABLE `posts` (
`pid` int(10) NOT NULL auto_increment,
`append_edit` tinyint(1) default '0',
`edit_time` int(10) default NULL,
`author_id` mediumint(8) NOT NULL default '0',
`author_name` varchar(32) default NULL,
`use_sig` tinyint(1) NOT NULL default '0',
`use_emo` tinyint(1) NOT NULL default '0',
`ip_address` varchar(16) NOT NULL default '',
`post_date` int(10) default NULL,
`icon_id` smallint(3) default NULL,
`post` mediumtext,
`queued` tinyint(1) NOT NULL default '0',
`topic_id` int(10) NOT NULL default '0',
`post_title` varchar(255) default NULL,
`new_topic` tinyint(1) default '0',
`edit_name` varchar(255) default NULL,
`post_key` varchar(32) NOT NULL default '0',
`post_parent` int(10) NOT NULL default '0',
`post_htmlstate` smallint(1) NOT NULL default '0',
`post_edit_reason` varchar(255) NOT NULL default '',
PRIMARY KEY (`pid`),
KEY `topic_id` (`topic_id`,`queued`,`pid`,`post_date`),
KEY `author_id` (`author_id`,`topic_id`),
KEY `post_date` (`post_date`),
KEY `ip_address` (`ip_address`),
KEY `post_key` (`post_key`),
FULLTEXT KEY `post` (`post`)
) ENGINE=MyISAM AUTO_INCREMENT=23 DEFAULT CHARSET=cp1251


Create Table: CREATE TABLE `topics` (
`tid` int(10) NOT NULL auto_increment,
`title` varchar(250) NOT NULL default '',
`description` varchar(70) default NULL,
`state` varchar(8) default NULL,
`posts` int(10) default NULL,
`starter_id` mediumint(8) NOT NULL default '0',
`start_date` int(10) default NULL,
`last_poster_id` mediumint(8) NOT NULL default '0',
`last_post` int(10) default NULL,
`icon_id` tinyint(2) default NULL,
`starter_name` varchar(32) default NULL,
`last_poster_name` varchar(32) default NULL,
`poll_state` varchar(8) default NULL,
`last_vote` int(10) default NULL,
`views` int(10) default NULL,
`forum_id` smallint(5) NOT NULL default '0',
`approved` tinyint(1) NOT NULL default '0',
`author_mode` tinyint(1) default NULL,
`pinned` tinyint(1) default NULL,
`moved_to` varchar(64) default NULL,
`total_votes` int(5) NOT NULL default '0',
`topic_hasattach` smallint(5) NOT NULL default '0',
`topic_firstpost` int(10) NOT NULL default '0',
`topic_queuedposts` int(10) NOT NULL default '0',
`topic_open_time` int(10) NOT NULL default '0',
`topic_close_time` int(10) NOT NULL default '0',
`topic_rating_total` smallint(5) unsigned NOT NULL default '0',
`topic_rating_hits` smallint(5) unsigned NOT NULL default '0',
PRIMARY KEY (`tid`),
KEY `topic_firstpost` (`topic_firstpost`),
KEY `last_post` (`forum_id`,`pinned`,`last_post`),
KEY `forum_id` (`forum_id`,`pinned`,`approved`),
KEY `starter_id` (`starter_id`,`forum_id`,`approved`),
KEY `last_post_sorting` (`last_post`,`forum_id`),
FULLTEXT KEY `title` (`title`)
) ENGINE=MyISAM AUTO_INCREMENT=4 DEFAULT CHARSET=cp1251
p.s.: Последние сообщения пытаетесь выбрать с форума? Вообще принято при постинге в форум проставлять в таблицу тем номер последнего сообщения, тогда такие проблемы пропадают как класс.

Типа того. Был бы последний ай-ди конечно бы вопроса не было.

У меня в итоге получился такой запрос


SELECT t.*, p.* FROM topics t
LEFT JOIN (SELECT MAX(pid) as pid, topic_id FROM posts GROUP BY topic_id) z ON z.topic_id=t.tid
LEFT JOIN posts p ON p.pid=z.pid
WHERE t.forum_id IN (1,2,3) ORDER BY t.tid DESC LIMIT 10;

не знаю просто на сколько быстро отработает вложенный select max(pid)

IL
На сайте с 20.04.2007
Offline
435
#10
edogs:
В большинстве случае на большинстве текущих версий и конфигураций мускула

Пример "меньшинства" будет?

На самом деле не могу не согласиться по поводу "случайной" (да чего соглашаться, так в мануале и написано), т.к. для выбора неаггрегированных полей в запросах с GROUP BY используется порядок расположения записей "как есть" (да-да, из той же серии, что и автоинкремент), а они в общем случае не упорядочены (есть, правда, исключения)..

Однако, используя то, что при выборе используется первое из найденных значений в совокупности с заранее упорядоченным набором записей можно получить нужный результат. Вполне возможно, причина в том, что формулировка "indeterminate value" гораздо проще, чем попытка пояснить, почему та или иная запись будет первой..

* Поведение стабильное (больше 6-ти лет точно), логичное и оптимальное (с точки зрения минимизации операций) и я (лично для себя) не вижу никаких причин, по которым разработчики могли бы поменять его. Кому интересно - может заглянуть в код MySQL.

** Естественно, никого не призываю использовать =)

И да.. если 2 записи с максимальным pid, то в предложенном мной варианте, будет выбрано только одно.. то самое, "произвольное" (если не задать дополнительно приоритет)

edogs:
mysql не определяет порядок выбора представителя группы если он не задан явно агрегирующими функциями.

А можно подробнее?

12

Авторизуйтесь или зарегистрируйтесь, чтобы оставить комментарий