Php 从多对多表对mysqli进行排序
我正在尝试制作一个基于web的内部消息系统,带有*amp系统,主要用于学习目的。我不知道这是否是一个琐碎的话题,但我有困难,所以请容忍我 目标是列出最后发送/接收的消息所排序的所有联系人。 当前未对其进行排序,SQL如下所示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 =
$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;