0

我正在制作一个类似于 tindler 的约会应用程序,用户可以在其中互相喜欢或不喜欢对方。如果两个用户都喜欢对方,他们应该能够互相聊天。我提出了以下查询来处理拉出您可以聊天/已经聊天的用户列表 - 我遇到的问题是我只想拉出最近的聊天消息,只是为了在你面前显示一点信息点击进入聊天本身。我的查询有效,但它返回最旧(最低 ID)的聊天记录,而不是最新的。Order by 似乎对返回正确结果没有影响。

$data = $this->db->select('users.id,display_name,city,state,gender,users_pictures.picture,users_chats.message')
                ->join('users_pictures','users_pictures.user_id=users.id')
                ->join('users_chats','users_chats.user_id=users.id OR users_chats.foreign_user_id=users.id','left outer')
                ->where('EXISTS (SELECT 1 FROM users_likes_dislikes ld WHERE (ld.foreign_user_id = '.$this->user_id.' AND ld.user_id=users.id AND ld.event_type=1) OR (SELECT 1 FROM users_likes_dislikes ld WHERE ld.foreign_user_id = users.id AND ld.user_id='.$this->user_id.' AND ld.event_type=1))', '', FALSE)
                ->where('NOT EXISTS (SELECT 1 FROM users_blocks ub WHERE (ub.foreign_user_id = users.id AND ub.user_id='.$this->user_id.') OR (SELECT 1 FROM users_blocks ub WHERE ub.foreign_user_id = '.$this->user_id.' AND ub.user_id=users.id))', '', FALSE)
                ->where('((users_chats.user_id='.$this->user_id.' OR users_chats.foreign_user_id='.$this->user_id.') OR (users_chats.user_id is NULL AND users_chats.foreign_user_id is NULL))')
                ->order_by('users_chats.id','DESC')
                ->group_by('users.id')              
                ->get('users')
                ->result_array();

这是 users_chats 的当前 mysql 表:

id user_id foreign_user_id message created
1 1 4 test 2013-05-22 15:42:44
2 1 4 test2 2013-05-22 15:44:38

我假设 order_by 将确保 test2 消息是显示的内容。

这是示例输出:

Array ( [0] => Array ( [id] => 4 [display_name] => testinguser [city] => west hills [state] => ca [gender] => 2 [picture] => testasdfasdf.jpg [message] => test ) )

任何帮助深表感谢 :)

编辑 - 查询本身(没有分组依据,这有效,但我需要将它分组到 user.id 以便我在数组中没有同一用户的多个条目):

SELECT
  `users`.`id`,
  `display_name`,
  `city`,
  `state`,
  `gender`,
  `users_pictures`.`picture`,
  `users_chats`.`message`
FROM (`users`)
  JOIN `users_pictures`
    ON `users_pictures`.`user_id` = `users`.`id`
  JOIN `users_chats`
    ON `users_chats`.`user_id` = `users`.`id`
       OR users_chats.foreign_user_id = users.id
WHERE EXISTS(SELECT
           1
         FROM users_likes_dislikes ld
         WHERE (ld.foreign_user_id = 1
            AND ld.user_id = users.id
            AND ld.event_type = 1)
          OR (SELECT
            1
              FROM users_likes_dislikes ld
              WHERE ld.foreign_user_id = users.id
              AND ld.user_id = 1
              AND ld.event_type = 1))
    AND NOT EXISTS(SELECT
             1
           FROM users_blocks ub
           WHERE (ub.foreign_user_id = users.id
              AND ub.user_id = 1)
            OR (SELECT
                  1
                FROM users_blocks ub
                WHERE ub.foreign_user_id = 1
                AND ub.user_id = users.id))
    AND ((users_chats.user_id = 1
       OR users_chats.foreign_user_id = 1)
      OR (users_chats.user_id is NULL
          AND users_chats.foreign_user_id is NULL))
ORDER BY `users_chats`.`created` DESC
4

3 回答 3

1

您的 group by 子句可能是这里的罪魁祸首。我相信分组操作首先发生,给你留下你的第一个结果。与其选择所有这些行(当有大量行时,它会花费更长的时间),您应该指定您想要多少行 - 在我看来,无论如何,这与这里的图片相差不远。指定你想要的数量,去掉 group by 子句,你应该按日期排序,因为你有一个日期列。这有帮助吗?

于 2013-05-22T20:09:15.043 回答
1

我不确定如何使用您的数据库抽象来做到这一点,但您想要的查询是

SELECT
   `users`.`id`,
   `display_name`,
   `city`,
   `state`,
   `gender`,
   `users_pictures`.`picture`,
   chats1.`message`
  FROM (`users`)
    JOIN `users_pictures`
      ON `users_pictures`.`user_id` = `users`.`id`
    JOIN `users_chats` AS chats1
      ON (chats1.`user_id` = `users`.`id`
         OR chats1.foreign_user_id = users.id)

重要的部分来了

         AND NOT EXISTS(
           SELECT *
             FROM users_chats AS chats2
             WHERE ((chats2.user_id = chats1.user_id AND chats2.foreign_user_id = chats1.foreign_user_id)
               OR (chats2.user_id = chats1.foreign_user_id AND chats1.user_id = chats2.foreign_user_id))
               AND chats2.created_date > chats1.created_date --which I assume is a time stamp
           )

这不漂亮,我知道。

  WHERE EXISTS(SELECT 1
    FROM users_likes_dislikes ld
      WHERE (ld.foreign_user_id = 1
        AND ld.user_id = users.id
        AND ld.event_type = 1)
        OR (SELECT 1
          FROM users_likes_dislikes ld
          WHERE ld.foreign_user_id = users.id
          AND ld.user_id = 1
          AND ld.event_type = 1)
    )
    AND NOT EXISTS(SELECT 1
       FROM users_blocks ub
       WHERE (ub.foreign_user_id = users.id
          AND ub.user_id = 1)
        OR (SELECT
              1
            FROM users_blocks ub
            WHERE ub.foreign_user_id = 1
            AND ub.user_id = users.id)
    )
    AND ((chats1.user_id = 1
        OR chats1.foreign_user_id = 1)
      OR (chats1.user_id is NULL
        AND chats1.foreign_user_id is NULL))
  ORDER BY `users_chats`.`created` DESC

基本上,只有在没有最新消息的情况下才能成功加入。有一些更好的本机解决方案 - TSQL(Microsoft SQL Server)有 CROSS APPLY,这在这里会很棒 - 但如果不了解更多关于您的数据库层的信息,我无法确定。您可能需要考虑重新构建您的聊天结构:

Users(int id /*also other user info*/)
chats(int id, datetime date_initiated, bool /*or bit, or short int*/ is_active)
chat_users (int chat_id, int user_id)
chat_messages (int chat_id, int user_id /*author*/, datetime date_sent, varchar(n) message)

使用这样的结构,您可以获得所有最新消息,如下所示:

SELECT *
  FROM Users AS u
    INNER JOIN chat_users AS cu
      ON u.id = cu.user_id
    INNER JOIN chats AS c
      ON c.id = cu.chat_id
        AND c.is_active = 1
    INNER JOIN chat_messages AS m
      ON m.chat_id = c.id
        AND NOT EXISTS (
          SELECT 1
            FROM chat_messages AS m2
              WHERE m2.chat_id = m.chat_id
                AND m.date_sent < m2.date_sent
        )
     INNER JOIN Users as sender
       ON m.user_id = sender.id
  WHERE u.id = ###
  ORDER BY m.date_sent DESC

您甚至可以创建一个“聊天最新消息”视图,例如:

CREATE VIEW Chat_Recent AS
  SELECT * /* WHATEVER YOU LIKE */ 
    FROM chats AS c
      INNER JOIN chat_messages AS m
        ON m.chat_id = c.id
          AND NOT EXISTS (
            SELECT 1
              FROM chat_messages AS m2
                WHERE m2.chat_id = m.chat_id
                  AND m.date_sent < m2.date_sent
          )
       INNER JOIN Users as sender
         ON m.user_id = sender.id
于 2013-05-22T20:35:14.943 回答
0

试试 MySQL MAX():

$this->db->join('(SELECT MAX(message) AS lastMsg FROM users_chats WHERE users_chats.user_id=users.id OR users_chats.foreign_user_id=users.id GROUP BY users.id)', 'left outer');

然后在您的选择中添加“lastMsg”。

于 2013-05-22T20:32:11.283 回答