|
|
|
| Здравствуйте, уважаемые пользователи форума.
Имеется такая таблица:
CREATE TABLE IF NOT EXISTS `PrivateMessages` (
`iID` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '№',
`sCreateDate` datetime NOT NULL COMMENT 'Дата и время отправки',
`iSenderID` int(10) unsigned NOT NULL COMMENT '№ отправителя',
`sMessage` text NOT NULL COMMENT 'Сообщение',
`iRecipientID` int(10) unsigned NOT NULL COMMENT '№ получателя'
PRIMARY KEY (`iID`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COMMENT='Приватные сообщения' AUTO_INCREMENT=1 ;
|
И вот такой запрос для обращения к ней:
SELECT * , IF( `iSenderID` = <userid>, `iRecipientID` , `iSenderID` ) AS `iCorrespondentID`
FROM (
SELECT *
FROM `PrivateMessages`
WHERE `iSenderID` = <userid> OR `iRecipientID` = <userid>
ORDER BY `iID` DESC
) AS `t`
GROUP BY `iCorrespondentID`
|
Как мы видим этот запрос является вложенным, что не есть хорошо для скорости его работы при больших объемах данных.
Помогите с него сделать два отдельных запроса по ключу. Заранее спасибо. | |
|
|
|
|
|
|
|
для: p.pavluxa
(29.08.2012 в 17:34)
| | А цель какая? Получить последнее письмо <userid> направленное ему или от него? Если да, то может поступить следующим образом?
SELECT
*,
IF( `iSenderID` = <userid>, `iRecipientID` , `iSenderID` ) AS `iCorrespondentID`
FROM
`PrivateMessages`
WHERE
`iSenderID` = <userid> OR `iRecipientID` = <userid>
ORDER BY
`iID` DESC
LIMIT 1
|
| |
|
|
|
|
|
|
|
для: cheops
(30.08.2012 в 07:08)
| | Цель правильная, но нужно получить последнее письмо одно, но количество пользователей с которыми были диалоги многи, следовательно записей должно возвращаться ровно столько сколько у него собеседников. Плюс в каждой записи дата и последнее сообщение. Поэтому Ваш вариант не подходит. | |
|
|
|
|
|
|
|
для: p.pavluxa
(29.08.2012 в 17:34)
| | Во-первых, без подзапроса тут не обойтись.
Во-вторых, объединяя вопрос из этой темы и из вашей же соседней, мне кажется ваш запрос не выполняет поставленной задачи.
И вообще он не правильный, т.к. у вас в селекте присутствуют поля (SELECT *) отсутствующие в предикате GROUP BY.
Для меня является большой тайной, почему MySQL не выдает на это ошибку, но работают такие конструкции не правильно - это точно. Т.е. в выдаче поля отсутствующие в GROUP BY могут принадлежать любой строке из группы.
Простой пример:
Тавлица:
CREATE TABLE tbl ( `id` int(10), `date` timestamp ) ENGINE=MyISAM
|
Данные:
INSERT INTO tbl VALUES(10,'2012-08-20 10:00:00'),(3,'2012-08-20 10:00:00'),(5,'2012-08-20 10:00:00')
|
Запрос:
SELECT * FROM tbl GROUP BY `date`
|
Вопрос:
Что вернет запрос? А главное - ПОЧЕМУ?
|
Правильный запрос должен в списке SELECT содержать только поля из GROUP BY. Все другие поля могут использоваться только с агрегатными функциями!
Например такой запрос:
SELECT max(id), `date` FROM tbl GROUP BY `date`
| однозначно вернет:
Теперь вернемся к вашему запросу и попробуем сделать его правильным.
/*<?*/
SELECT iSenderID
, iRecipientID
, max(`date`)dt
, /* кореллирующий подзапрос */
( SELECT sMessage
FROM PrivateMessages
WHERE ( (iSenderID = <userid> AND iRecipientID=pm.iRecipientID) OR
(iRecipientID = <userid> AND iSenderID=pm.iSenderID) ) AND
`date`=max(pm.`date`)
LIMIT 1 /* ограничение на случай, если имеется несколько подходящих строк */
)ms
FROM PrivateMessages pm
WHERE iSenderID = <userid> OR iRecipientID = <userid>
GROUP BY iSenderID, iRecipientID
|
Но по большому счету и этот запрос не совсем верный.
Например если имеются такие данные:
INSERT INTO PrivateMessages VALUES
(1,'2012-08-20 10:00:00',10,'Привет',20),
(2,'2012-08-20 10:00:00',20,'Пока',10)
| , т.е. два пользователя написали друг другу одновременно, то для пользователя <10> будет выведено:
10 | 20 | 2012-08-20 10:00:00 | 'Привет'
20 | 10 | 2012-08-20 10:00:00 | 'Привет'
| , что, как вы понимаете, не верно.
Считаю, что после такой лекции у меня есть моральное право дать вам "домашнее задание" исправить этот запрос =)))
_____________
[UPD]
Перепрятушки =)
Запрос вернет все правильно. Но он для пользователя <userid>, если с пользователем например <20> есть и входящие и исходящие, выведет последнее входящее и последнее исходящее.
Если вам нужно только одно последнее сообщение, не важно вход-е или исход-е, то попробуйте исправить сами =)
Но вложенность запросов придется еще увеличить! | |
|
|
|
|
|
|
|
для: Sfinks
(30.08.2012 в 11:19)
| | Эм... Не понял почему мой запрос работает неверно | |
|
|
|
|
|
|
|
для: p.pavluxa
(31.08.2012 в 10:34)
| | Ну я уж и не знаю что тут еще добавить!...
Ну проверьте свой запрос на таких данных:
INSERT INTO `PrivateMessages` (`iID`, `sCreateDate`, `iSenderID`, `sMessage`, `iRecipientID`) VALUES
(NULL, '2012-08-31 00:00:00', '10', 'последнее сообщение', '20'),
(NULL, '2012-08-22 00:00:00', '10', 'первое сообщение', '20'),
(NULL, '2012-08-26 00:00:00', '10', 'промежуточное сообщение', '20');
| для <userid>=10 и проверьте мой (только исправьте в нем везде `date` на sCreateDate - я опечатался) и сравните результат. | |
|
|
|
|