У меня есть таблица базы данных, называемая «mesg» со следующей структурой:
receiver_id | sender_id | сообщение | временная метка | читать
Пример:
2 *(«me)* | 6 *(«nice girl)* | 'I like you, more than ghoti' | yearsago | 1 *(«seen it)* 2 *(«me)* | 6 *(«nice girl)* | 'I like you, more than fish' | now | 1 *(«seen it)* 6 *(«nice girl)* | 2 *(«me)* | 'Hey, wanna go fish?' | yearsago+1sec | 0 *(«she hasn't seen it)*
Это довольно сложная вещь, которую я хочу достичь.
Я хочу получить: последнее сообщение (= ORDER BY time DESC) + «имя контакта» + время для каждого «беседы».
Например:
From: **Bas Kreuntjes** *(« The message from bas is the most recent)* Hey $py, How are you doing... From: **Sophie Naarden** *(« Second recent)* Well hello, would you like to buy my spam? ... *(«I'll work on that later >p)* To: **Melanie van Deijk** *(« My message to Melanie is 3th)* And? Did you kiss him? ...
Это грубый результат.
ВОПРОС: Может кто-нибудь помочь мне настроить хорошую команду SQL. Это будет в то время как loup
<?php $sql = "????"; $result = mysql_query($sql); while($fetch = mysql_fetch_assoc($result)){ ?> <div class="message-block"> <h1><?php echo($fetch['uname']); ?></h1> <p><?php echo($fetch['message']); ?></p> <p><?php echo($fetch['time']); ?></p> </div> <?php } ?>
Надеюсь, мои объяснения достаточно хороши, если нет, скажите, пожалуйста. Пожалуйста, не обращайте внимания на мой английский и голландские имена (я сам голландский). Не стесняйтесь исправить мой английский.
UPDATE1: Лучшее, что у меня есть до сих пор: но я не хочу показывать больше одного разговора … u = таблица пользователя m = таблица сообщений
SELECT u.uname, m.message, m.receiver_uid, m.sender_uid, m.time FROM m, u WHERE (m.receiver_uid = '$myID' AND u.uid = m.sender_uid) OR (m.sender_uid = '$myID' AND u.uid = m.receiver_uid) ORDER BY time DESC;
Скудно … но выполнимо. Постройте ответ на один кусок за раз.
Учитывая конкретный ссылочный пользователь («я») в примерах, вам нужно найти все сообщения между «мной» и другим человеком. Для каждого такого другого человека вы хотите найти одно сообщение с самой последней отметкой времени.
Давайте создадим идентификатор беседы, связав все сообщения вместе. Поскольку нас интересует одна сторона («я») за раз, мы можем использовать идентификатор другого человека для идентификации разговора.
SELECT m.recipient_uid AS conversation, m.recipient_uid AS recipient_uid, m.sender_uid AS sender_uid, m.timestamp AS timestamp FROM mesg AS m WHERE m.sender_uid = '$myID' UNION SELECT m.sender_uid AS conversation, m.recipient_uid AS recipient_uid, m.sender_uid AS sender_uid, m.timestamp AS timestamp FROM mesg AS m WHERE m.recipient_uid = '$myID'
Это позволяет прокручивать все чаты вместе с одним и тем же идентификатором беседы.
Теперь вам нужно сгруппировать это по разговору, чтобы найти разговор и самое последнее время; для этого вам не нужны другие столбцы (recipient_uid или sender_uid):
SELECT conversation, MAX(timestamp) AS max_timestamp FROM (SELECT m.recipient_uid AS conversation, m.timestamp AS timestamp FROM mesg AS m WHERE m.sender_uid = '$myID' UNION SELECT m.sender_uid AS conversation, m.timestamp AS timestamp FROM mesg AS m WHERE m.recipient_uid = '$myID') AS c GROUP BY conversation
Итак, для каждого разговора мы теперь знаем самую последнюю метку времени. Нам просто нужно присоединиться к этой информации с предыдущим запросом, чтобы получить большинство деталей:
SELECT c.recipient_uid, c.sender_uid, c.timestamp FROM (SELECT conversation, MAX(timestamp) AS max_timestamp FROM (SELECT m.recipient_uid AS conversation, m.timestamp AS timestamp FROM mesg AS m WHERE m.sender_uid = '$myID' UNION SELECT m.sender_uid AS conversation, m.timestamp AS timestamp FROM mesg AS m WHERE m.recipient_uid = '$myID') AS c GROUP BY conversation ) AS x JOIN (SELECT m.recipient_uid AS conversation, m.recipient_uid AS recipient_uid, m.sender_uid AS sender_uid, m.timestamp AS timestamp FROM mesg AS m WHERE m.sender_uid = '$myID' UNION SELECT m.sender_uid AS conversation, m.recipient_uid AS recipient_uid, m.sender_uid AS sender_uid, m.timestamp AS timestamp FROM mesg AS m WHERE m.recipient_uid = '$myID' ) AS c ON c.conversation = x.conversation AND c.timestamp = x.max_timestamp
Поскольку вы сказали, что хотите иметь имена, вы можете расширить это, чтобы присоединиться к таблице пользователей дважды:
SELECT c.recipient_uid, c.sender_uid, c.timestamp, u1.uname AS recipient, u2.uname AS sender FROM (SELECT conversation, MAX(timestamp) AS max_timestamp FROM (SELECT m.recipient_uid AS conversation, m.timestamp AS timestamp FROM mesg AS m WHERE m.sender_uid = '$myID' UNION SELECT m.sender_uid AS conversation, m.timestamp AS timestamp FROM mesg AS m WHERE m.recipient_uid = '$myID') AS c GROUP BY conversation ) AS x JOIN (SELECT m.recipient_uid AS conversation, m.recipient_uid AS recipient_uid, m.sender_uid AS sender_uid, m.timestamp AS timestamp FROM mesg AS m WHERE m.sender_uid = '$myID' UNION SELECT m.sender_uid AS conversation, m.recipient_uid AS recipient_uid, m.sender_uid AS sender_uid, m.timestamp AS timestamp FROM mesg AS m WHERE m.recipient_uid = '$myID' ) AS c ON c.conversation = x.conversation AND c.timestamp = x.max_timestamp JOIN user AS u1 ON u1.uid = c.recipient_uid JOIN user AS u2 ON u2.uid = c.sender_uid
Там – это весело. Я бы не хотел писать это за один раз, но создавал кусок за раз, это не слишком устрашающе (хотя это не тривиально).
CREATE TABLE user ( uid INTEGER NOT NULL PRIMARY KEY, uname VARCHAR(30) NOT NULL );
DATETIME YEAR TO SECOND – забавный способ написания TIMESTAMP (в IBM Informix Dynamic Server – где я тестировал это).
CREATE TABLE mesg ( recipient_uid INTEGER NOT NULL REFERENCES user(uid), sender_uid INTEGER NOT NULL REFERENCES user(uid), message VARCHAR(255) NOT NULL, timestamp DATETIME YEAR TO SECOND NOT NULL, PRIMARY KEY (recipient_uid, sender_uid, timestamp), READ CHAR(1) NOT NULL );
INSERT INTO USER VALUES(2, 'My Full Name'); INSERT INTO USER VALUES(6, 'Her Full Name'); INSERT INTO USER VALUES(3, 'Dag Brunner');
INSERT INTO mesg VALUES(2, 6, 'I like you, more than ghoti', '2008-01-01 00:05:03', 1); INSERT INTO mesg VALUES(2, 6, 'I like you, more than fish', '2011-01-15 13:45:09', 1); INSERT INTO mesg VALUES(6, 2, 'Hey, wanna go fish?', '2008-01-01 09:30:47', 0); INSERT INTO mesg VALUES(2, 3, 'Wanna catch a beer?', '2011-01-14 13:45:09', 1); INSERT INTO mesg VALUES(3, 2, 'Sounds good to me!!', '2011-01-14 13:55:39', 1); INSERT INTO mesg VALUES(3, 6, 'Heading home now???', '2010-12-31 12:27:41', 1); INSERT INTO mesg VALUES(6, 3, 'Yes - on the bus!!!', '2010-12-31 13:55:39', 1);
Conv Recv Send When 3 2 3 2011-01-14 13:45:09 3 3 2 2011-01-14 13:55:39 6 2 6 2008-01-01 00:05:03 6 2 6 2011-01-15 13:45:09 6 6 2 2008-01-01 09:30:47
Conv Most Recent 3 2011-01-14 13:55:39 6 2011-01-15 13:45:09
Recv Send When 3 2 2011-01-14 13:55:39 2 6 2011-01-15 13:45:09
Recv Send When Receiver Sender 3 2 2011-01-14 13:55:39 Dag Brunner My Full Name 2 6 2011-01-15 13:45:09 My Full Name Her Full Name
Ничего себе, я не часто получаю часть SQL, которая является этим сложным сразу с первого раза, но в этом случае, помимо поездки по методу receiver_uid vs recipient_uid на первой итерации, она работала правильно в первый раз.
Опуская параметр «кто» (или «я» или «$ myID»), мы можем придумать общее решение для последнего сообщения в любом из разговоров между двумя людьми. Разговор определяется идентификатором участника с более высоким и нижним (или наоборот). В противном случае он очень похож на предыдущий.
SELECT c.recipient_uid, c.sender_uid, c.timestamp, u1.uname AS recipient, u2.uname AS sender FROM (SELECT conv01, conv02, MAX(timestamp) AS max_timestamp FROM (SELECT m.recipient_uid AS conv01, m.sender_uid AS conv02, m.timestamp AS timestamp FROM mesg AS m WHERE m.sender_uid < m.recipient_uid UNION SELECT m.sender_uid AS conv01, m.recipient_uid AS conv02, m.timestamp AS timestamp FROM mesg AS m WHERE m.sender_uid > m.recipient_uid ) AS C GROUP BY conv01, conv02 ) AS x JOIN (SELECT m.recipient_uid AS conv01, m.sender_uid AS conv02, m.recipient_uid AS recipient_uid, m.sender_uid AS sender_uid, m.timestamp AS timestamp FROM mesg AS m WHERE m.sender_uid < m.recipient_uid UNION SELECT m.sender_uid AS conv01, m.recipient_uid AS conv02, m.recipient_uid AS recipient_uid, m.sender_uid AS sender_uid, m.timestamp AS timestamp FROM mesg AS m WHERE m.sender_uid > m.recipient_uid ) AS C ON c.conv01 = x.conv01 AND c.conv02 = x.conv02 AND c.timestamp = x.max_timestamp JOIN USER AS u1 ON u1.uid = C.recipient_uid JOIN USER AS u2 ON u2.uid = C.sender_uid;
Recv Send When Recipient Sender 6 3 2010-12-31 13:55:39 Her Full Name Dag Brunner 2 6 2011-01-15 13:45:09 My Full Name Her Full Name 3 2 2011-01-14 13:55:39 Dag Brunner My Full Name
Это довольно сложная вещь, которую я хочу достичь.
На самом деле, нет.
Вы можете получить время последнего сообщения, просто используя:
SELECT receiver_id, sender_id, MAX(timestamp) as mtime FROM mesg GROUP BY receiver_id, sender_id
(Вероятно, вы хотите добавить класс where, чтобы фильтровать отправителем / получателем) И затем, чтобы получить фактическое сообщение ….
SELECT m2.* FROM mesg m2, (SELECT receiver_id, sender_id, MAX(timestamp) as mtime FROM mesg GROUP BY receiver_id, sender_id) ilv WHERE m2.sender_id=ilv.seder_id AND m2.receiver_id=ilv.receiver_id AND m2.timestamp=ilv.mtime;
Это, однако, довольно неэффективно, так как оно открывает 2 курсора на столе, более эффективное решение (и если вы запускаете очень старую версию mysql, единственное решение) – использовать макс concat трюк .
Я оставлю это упражнением для вас.
Я усовершенствовал сценарий Джонатана: Неправда (ОБНОВЛЕНИЕ)
Первый шаг работает:
SELECT message, receiver_uid AS receiver, sender_uid AS sender, time, sender_uid AS me, receiver_uid AS contact FROM messages WHERE sender_uid = '$me' ) UNION ( SELECT message, receiver_uid AS receiver, sender_uid AS sender, time, receiver_uid AS me, sender_uid AS contact FROM messages WHERE receiver_uid = '$me' ) ORDER BY time DESC
Он дает хороший чистый список, который говорит мне, являюсь ли я отправителем или нет, и кто мой контакт. Но комбинация во второй части [MAX () и GROUP BY] не работает так, как я хочу.
Он не выбирает самую последнюю часть разговора (отправлять или получать не должны иметь значения). Он скорее просто выбирает первые новые ID-встречи. Поэтому MAX () не выполняет свою работу.
SELECT m.message, m.receiver, m.sender, max(m.time) « doesn't work well... AS time, m.me, m.contact, u.ufirstname FROM( ( SELECT message, receiver_uid AS receiver, sender_uid AS sender, time, sender_uid AS me, receiver_uid AS contact FROM messages WHERE sender_uid = '$me' ) UNION ( SELECT message, receiver_uid AS receiver, sender_uid AS sender, time, receiver_uid AS me, sender_uid AS contact FROM messages WHERE receiver_uid = '$me' ) ORDER BY time DESC) AS m, users AS u WHERE u.uid = m.contact GROUP BY m.contact «This one does not do what we want it to do :( ORDER BY time DESC;
В каком формате время в базе данных должно использовать функцию MAX (). Макс () не выбирает самую последнюю дату, это то, что происходит неправильно.