Php 从多对多表对mysqli进行排序

Php 从多对多表对mysqli进行排序,php,mysql,sql,mysqli,Php,Mysql,Sql,Mysqli,我正在尝试制作一个基于web的内部消息系统,带有*amp系统,主要用于学习目的。我不知道这是否是一个琐碎的话题,但我有困难,所以请容忍我 目标是列出最后发送/接收的消息所排序的所有联系人。 当前未对其进行排序,SQL如下所示 $query = "SELECT username, user.id as user_id, (SELECT COUNT(message_read) FROM message_user WHERE message_read = 0 AND sent_id =

我正在尝试制作一个基于web的内部消息系统,带有*amp系统,主要用于学习目的。我不知道这是否是一个琐碎的话题,但我有困难,所以请容忍我

目标是列出最后发送/接收的消息所排序的所有联系人。 当前未对其进行排序,SQL如下所示

$query = "SELECT username, user.id as user_id,  

(SELECT COUNT(message_read)  
FROM message_user  
WHERE message_read = 0 
AND sent_id = user_id  
AND receive_id = {$userId}) as unread  

FROM user  
WHERE user.id IN  
(SELECT contact_id FROM allowed_contact WHERE user_id = {$userId})   
;";
表的结构为:
user
表有一个
id

链接到
message\u user
表,该表具有
发送id
接收id

message\u user
有一个与
message.id
相对应的
message\u id
消息
表有一个
时间戳


我希望用SQL完成这项工作,但如果归结到PHP,我会选择使用它。

使用2
左连接
不同的
(未经测试):

这很有效

SELECT `u`.`id` AS user_id, username,
(SELECT COUNT(message_user.message_read)  
FROM message_user  
WHERE message_user.message_read = 0 
AND sent_id = user_id  
AND receive_id = {$userId}) as unread  

FROM `user` AS `u`
LEFT JOIN `message_user` AS `mu` 
ON 
    (CASE WHEN `u`.`id` != {$userId}
        THEN `u`.`id` = `mu`.`sent_id`
        WHEN `mu`.`sent_id` = {$userId} AND `mu`.`receive_id` = {$userId}
        THEN `u`.`id` = `mu`.`sent_id`
    END)
OR  
    (CASE WHEN `u`.`id` != {$userId}
        THEN `u`.`id` = `mu`.`receive_id`
    END)

LEFT JOIN `message` AS `m` ON `m`.`id` = `mu`.`message_id`

WHERE u.id IN  
(SELECT contact_id FROM allowed_contact WHERE user_id = {$userId})
GROUP BY u.id
ORDER BY MAX(`m`.`timestamp`) DESC;
解决了我遇到的问题


@Andreas感谢您的时间和帮助。

它仍然没有正确排序,当我将
时间戳添加到
选择DISTINCT
时,它会按顺序排序,但带有重复性。警告:使用
mysqli
时,您应该使用参数化查询,并将用户数据添加到查询中。不要使用字符串插值或串联来完成此操作,因为您已经创建了严重的错误。切勿将
$\u POST
$\u GET
数据直接放入查询中,如果有人试图利用您的错误,这可能非常有害。
$userId
是mysql从数据库中自动生成的id。这个值不是由用户提供的。您这么说,但我敢打赌您代码中的某个地方的钱是
$userId=$\u GET['userId']
。不要冒险。这看起来太复杂了,但这是因为你采用了不同寻常的模式。我认为您可以调整您的表,使这种查询更容易。别忘了按比例测试类似的内容,必要时加载数万条或数百万条虚拟消息,以确保正确地索引内容。现在您让我查看模式,我可以在
消息\u用户
上添加时间戳。它仍然几乎同样复杂,但是通过删除第二个
左连接
可以提高性能。我可以这样说,如果一条消息被发送两次,那么它应该被接收到的时间看到,而不是被创建的时间。我想我太关注细节了,忘了看全貌,谢谢。
SELECT `u`.`id` AS user_id, username,
(SELECT COUNT(message_user.message_read)  
FROM message_user  
WHERE message_user.message_read = 0 
AND sent_id = user_id  
AND receive_id = {$userId}) as unread  

FROM `user` AS `u`
LEFT JOIN `message_user` AS `mu` 
ON 
    (CASE WHEN `u`.`id` != {$userId}
        THEN `u`.`id` = `mu`.`sent_id`
        WHEN `mu`.`sent_id` = {$userId} AND `mu`.`receive_id` = {$userId}
        THEN `u`.`id` = `mu`.`sent_id`
    END)
OR  
    (CASE WHEN `u`.`id` != {$userId}
        THEN `u`.`id` = `mu`.`receive_id`
    END)

LEFT JOIN `message` AS `m` ON `m`.`id` = `mu`.`message_id`

WHERE u.id IN  
(SELECT contact_id FROM allowed_contact WHERE user_id = {$userId})
GROUP BY u.id
ORDER BY MAX(`m`.`timestamp`) DESC;