我可以使用我的SQL命令的一些帮助

时间:2011-01-15 23:08:27

标签: php mysql sql

我有一个名为'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时间DESC)+'联系人姓名'+每个'对话'的时间。

  • 联系人姓名= uname WHERE uid ='联系人ID'(用户名在另一个表中)
  • 联络ID = if(sessionID *(«me)* = sender_id){receiver_id} else {sender_id}
  • 会话 = 收件人或我=发件人

例如:

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命令。 这将是while 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:我到目前为止最好: 但我不希望出现多个对话...... 你=用户表 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;

4 个答案:

答案 0 :(得分:3)

可爱......但可行。一次建立一个答案。

构建查询 - 一步一步

在示例中给定一个特定的参考用户('我'),您需要找到'我'和另一个人之间的所有消息。对于每个这样的其他人,您希望找到具有最新时间戳的一条消息。

查询1

让我们建立会话ID,将所有消息链接在一起。由于我们一次对一方('我')感兴趣,我们可以使用其他人的ID来识别对话。

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'

这使您可以将所有聊天内容与个人一起使用相同的会话ID。

查询2

现在您需要通过对话对其进行分组以找到对话和最近的时间;为此,您不需要其他(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

查询3

因此,对于每次对话,我们现在都知道最新的时间戳。我们只需要将这些信息与之前的查询一起加入,以获取大部分细节:

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

查询4

既然你说你也想要名字,你可以扩展它以与users表连接两次:

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
);

Mesg Table

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');

Mesg数据

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);

结果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

结果2

Conv    Most Recent
3       2011-01-14 13:55:39
6       2011-01-15 13:45:09

结果3

Recv    Send    When
3       2       2011-01-14 13:55:39
2       6       2011-01-15 13:45:09

结果4

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和recipient_uid之外,它确实首先正常工作时间。


一般解决方案

省略'who'(或'我'或'$ myID')参数,我们可以在两个人之间的任何对话中为最新消息提供一般解决方案。会话由较高和较低(或反之亦然)参与者ID标识。否则,它与前一个非常相似。

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

答案 1 :(得分:0)

  

这是我想要实现的一件非常棘手的事情。

不是。

您可以使用以下方式获取最后一条消息的时间:

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,唯一的解决方案)是使用max concat trick

我会把它作为练习让你锻炼身体。

答案 2 :(得分:0)

我已经完善了Jonathan脚本:不正确(更新)

第一步有效:

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 ot遭遇。所以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;

答案 3 :(得分:0)

数据库中的时间需要使用哪种格式的函数MAX()。 Max()不会选择最近的日期,这就是出错的地方。