我正在创建一个类似于tindler的约会应用,用户可以相互喜欢或不喜欢。如果两个用户都喜欢彼此,他们应该能够互相聊天。我已经提出了以下查询来处理拉出你可以聊天/已经聊过的用户列表 - 我遇到的问题是我只想拉最近的聊天消息,只是为了在你之前显示一点点模糊点击聊天本身。我的查询有效,但它返回最旧的(最低ID)聊天记录,而不是最新的。排序依据似乎不会对返回正确的结果产生影响。
$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
答案 0 :(得分:1)
你的group by子句可能是罪魁祸首。我相信分组操作首先发生,留下你的第一个结果。 而不是选择所有这些行(当需要更长时间时需要更长时间),你应该指定你想要的数量 - 它看起来像我这里的图片并不太远,无论如何。指定您想要的数量,摆脱group by子句,并且您应该按日期排序,因为您有一个日期列。 这有帮助吗?
答案 1 :(得分:1)
我不确定如何使用db Abstraction,但您想要的查询是
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
答案 2 :(得分:-1)
尝试使用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”。