Задавайте вопросы, мы ответим
Вы не зашли.
Всем привет. Столкнулся с проблемкой. Имеется таблица в БД, где хранятся сообщения всех пользователей.
Имеется 3 основных поля:
ID_message - id сообщения
ID_user - id автора сообщения
ID_user_to - id адресата
При переходе в личные сообщения пользователь должен увидеть список всех своих сообщений, уникальных по пользователю. Выбрав которое он может просмотреть всю переписку с выбранным пользователем. Нужен запрос для получения информации для отображения этих сообщений. С SQL я не дружу и сделал такую "красоту" :
$currentUserId = User_User::getId(); - id пользователя, которым смотрит свою переписку
Получаем id всех пользователей с которыми вел переписку наш пользователь сообщения( где он является автором либо адресатом)
$stmt = "SELECT `message`.`ID_user_to` id
FROM `message`
WHERE `message`.`ID_user`='" . $currentUserId . "'
UNION
SELECT `message`.`ID_user` id
FROM `message`
WHERE `message`.`ID_user_to`='" . $currentUserId . "'";
$arrIds = $objDB->selectSimpleArray($stmt); // Вся переписка текущего пользователя
Перебираем эти id, для каждого пользователя смотрим все сообщения, где он автор а получатель наш пользователь или он - адресат, а автор - наш пользователь, сортируем по дате и берём последнее...Но мой вариант вообще не работает, я знаю почему, но просто не знаю как реализовать правильно + с наилучшим быстродействием.....
foreach ($arrIds as $id) {
$stmt = "SELECT `message`.`text`,`message`.`created_at`,`message`.`is_read_at`, `user`.`e_mail`
FROM `message`
IF(`message`.`ID_user`='". $currentUserId ."') INNER JOIN `user`
ON `user`.`ID_user` = `message`.`ID_user_to`)
IF(`message`.`ID_user_to`='" . $currentUserId . "')INNER JOIN `user`
ON `user`.`ID_user`=`message`.ID_user)
WHERE `message`.`ID_user`='" . $id . "' AND `message`.`ID_user_to`='" . $currentUserId . "' OR `message`.`ID_user_to`='" . $id . "' AND `message`.`ID_user`='" . $currentUserId . "' ORDER BY `message`.`created_at` DESC LIMIT 1";
$arrMessages[] = $objDB->selectOne($stmt); // Получаем последнее сообщение переписки пользователя с собеседником $id
}
return $arrMessages;
Подскажите, пожалуйста, возможные решения этой задачи....
Отредактированно Сергей133 (24.04.2012 21:52:41)
Неактивен
Неактивен
Легче не стало, попробовал все описанные там способы, везде одна и та же проблема...
Требуется получить для текущего пользователя всю последнюю переписку. Допусти Id пользователя, который зашёл в "Мои сообщения" = 5. В Базе данных имеется 5 записей с таким id:
ID_user = 5 ID_user_to = 2 created_at = 01.01.2000
ID_user = 5 ID_user_to = 2 created_at = 02.01.2000
ID_user = 3 ID_user_to = 5 created_at = 01.01.2000
ID_user = 2 ID_user_to = 5 created_at = 03.01.2000
ID_user = 5 ID_user_to = 3 created_at = 07.01.2000
Значит пользователь должен увидеть две строки:
Переписка с пользователем ID=3 Последнее сообщение: 07.01.2000, текст сообщения
Переписка с пользователем ID=2 Последнее сообщение: 03.01.2000, текст сообщения
Я сделал запрос:
SELECT ID_user,ID_user_to, MAX(created_at)
FROM `message`
WHERE ID_user = 5 OR ID_user_to = 5
GROUP BY ID_user,ID_user_to
ORDER BY created_at DESC
В этом примере он вернёт строки :
ID_user = 5 ID_user_to = 3 created_at = 07.01.2000
ID_user = 2 ID_user_to = 5 created_at = 03.01.2000
ID_user = 5 ID_user_to = 2 created_at = 02.01.2000
ID_user = 3 ID_user_to = 5 created_at = 01.01.2000
Как сделать так, чтобы вместо этого он выводил:
ID_user = 5 ID_user_to = 3 created_at = 07.01.2000
ID_user = 2 ID_user_to = 5 created_at = 03.01.2000 ?
Ведь сообщения от id=5 для id=2 и от id=2 для id=5 относятся к одной и той же переписке.
Неактивен
Неактивен
vasya написал:
SELECT ID_user,ID_user_to, MAX(created_at) from
(SELECT ID_user,ID_user_to, created_at FROM `message` WHERE ID_user = 5
union
SELECT ID_user,ID_user_to, created_at FROM `message` WHERE ID_user_to = 5) t group by ID_user order by 3 desc;
По моему group by ID_user тут испортит малину в случае если есть только такие записи.
ID_user = 5 ID_user_to = 2 created_at = 01.01.2000
ID_user = 5 ID_user_to = 3 created_at = 07.01.2000
Первое что пришло в голову
Неактивен
Последний вариант тоже неверен. Группируя, он берёт абсолютно случайные сообщения, добавляя при этом в конце ячейку с датой последнего сообщения переписки.
Отредактированно Сергей133 (27.04.2012 11:20:12)
Неактивен
evgeny написал:
По моему group by ID_user тут испортит малину в случае если есть только такие записи.
ID_user = 5 ID_user_to = 2 created_at = 01.01.2000
ID_user = 5 ID_user_to = 3 created_at = 07.01.2000
Да, вы правы, что-то совсем не то я написал. Правильно будет
evgeny написал:
Первое что пришло в голову
SELECT MAX(created_at),ID_user,ID_user_to,cross_id FROM (
SELECT ID_user,ID_user_to, created_at,(ID_user+ID_user_to) cross_id FROM `message` WHERE ID_user = 5 OR ID_user_to = 5
) GROUP BY cross_id order by 1 desc;
В этом варианте нужно будет делать join, так как ID_user,ID_user_to выбираются без группирующей функции.
Неактивен
Последний запрос тоже неверен, там при группировке могут меняться местами id_user и id_user_to у сообщений....
Нашёл решение:
SELECT `user`.`e_mail`,`user`.`ID_user`, `temptable`.*
FROM `user`
LEFT JOIN (
SELECT `message`.*
FROM `message`
WHERE `message`.`ID_user`=5 OR `message`.`ID_user_to`=5
ORDER BY `message`.`created_at` DESC
)temptable
ON (`user`.ID_user = `temptable`.`ID_user`) OR (`user`.ID_user = `temptable`.`ID_user_to`)
WHERE `user`.`ID_user` IN (
SELECT `ID_user`
FROM `message`
WHERE `ID_user_to` = 5
UNION
SELECT `ID_user_to`
FROM `message`
WHERE `ID_user` = 5
)
GROUP BY `user`.`ID_user`
Отредактированно Сергей133 (27.04.2012 16:54:29)
Неактивен
Сергей133 написал:
Последний запрос тоже неверен, там при группировке могут меняться местами id_user и id_user_to у сообщений....
Нашёл решение:
SELECT `user`.`e_mail`,`user`.`ID_user`, `temptable`.*
FROM `user`
LEFT JOIN (
SELECT `message`.*
FROM `message`
WHERE `message`.`ID_user`=5 OR `message`.`ID_user_to`=5
ORDER BY `message`.`created_at` DESC
)temptable
ON (`user`.ID_user = `temptable`.`ID_user`) OR (`user`.ID_user = `temptable`.`ID_user_to`)
WHERE `user`.`ID_user` IN (
SELECT `ID_user`
FROM `message`
WHERE `ID_user_to` = 5
UNION
SELECT `ID_user_to`
FROM `message`
WHERE `ID_user` = 5
)
GROUP BY `user`.`ID_user`
Это очень тяжёлый запрос.
Вот, проверьте этот вариант , по идее должен быть самым оптимальным вариантом.
Отредактированно evgeny (27.04.2012 22:29:21)
Неактивен