我有下表
+--------+-----------+---------+----------------------------+---------------------+--------------------+
| msg_id | user_from | user_to | msg_text | msg_time | msg_read |
+--------+-----------+---------+----------------------------+---------------------+--------------------+
| 1 | 1 | 72 | Hello Mark from Andy | 2014-09-18 12:44:09 | 2014-09-20 12:44:09|
| 2 | 72 | 1 | Hello Andy from Mark | 2014-09-22 12:45:26 | 2014-09-28 12:45:26|
| 3 | 1 | 72 | Back to you Mark from Andy | 2014-10-18 12:46:01 | |
| 4 | 12388 | 1 | Hello Andy from Graham | 2014-09-20 12:45:37 | 2014-09-20 12:46:37|
| 5 | 1 | 12388 | Hello Graham from Andy | 2014-09-20 12:51:08 | |
| 6 | 106 | 1 | Hello Andy from Carol | 2015-04-18 12:47:04 | |
+--------+-----------+---------+----------------------------+---------------------+--------------------+
由于SQLFiddle目前处于关闭状态,这是查询。
-- ----------------------------
-- Table structure for `messages`
-- ----------------------------
DROP TABLE IF EXISTS `messages`;
CREATE TABLE `messages` (
`msg_id` int(11) NOT NULL AUTO_INCREMENT,
`user_from` int(11) NOT NULL,
`user_to` int(11) NOT NULL,
`msg_text` text,
`msg_time` datetime DEFAULT NULL,
`msg_read` datetime DEFAULT NULL,
PRIMARY KEY (`msg_id`),
KEY `IX_MESSAGES` (`user_from`)
) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=latin1;
-- ----------------------------
-- Records of messages
-- ----------------------------
INSERT INTO `messages` VALUES ('1', '1', '72', 'Hello Mark from Andy', '2014-09-18 12:44:09', '2014-09-20 12:44:09');
INSERT INTO `messages` VALUES ('2', '72', '1', 'Hello Andy from Mark', '2014-09-22 12:45:26', '2014-09-28 12:45:26');
INSERT INTO `messages` VALUES ('3', '1', '72', 'Back to you Mark from Andy', '2014-10-18 12:46:01', null);
INSERT INTO `messages` VALUES ('4', '12388', '1', 'Hello Andy from Graham', '2014-09-20 12:45:37', '2014-09-20 12:46:37');
INSERT INTO `messages` VALUES ('5', '1', '12388', 'Hello Graham from Andy', '2014-09-20 12:51:08', null);
INSERT INTO `messages` VALUES ('6', '106', '1', 'Hello Andy from Carol', '2015-04-18 12:47:04', null);
正如您可能已经猜到的,这是一个消息传递系统。为了在Facebook风格的收件箱中显示,我想提取一个结果集,该结果集显示特定用户与之通信的不同用户,但我还想包括最新消息以及消息时间以及是否已读取,请记住,最新消息可能来自发件人或收件人。
获得不同的用户非常容易。我只是按如下方式使用UNION:
SELECT
t.user_id,
t.msg_read,
t.msg_time,
t.msg_text
FROM
(
(
SELECT
m.user_from AS user_id,
m.msg_time,
m.msg_text,
m.msg_read
FROM
messages m
WHERE
m.user_to = 1
)
UNION
(
SELECT
m.user_to AS user_id,
m.msg_time AS msg_time,
m.msg_text,
m.msg_read
FROM
messages m
WHERE
m.user_from = 1
)
) t
GROUP BY user_id
这会产生:
+---------+--------------------+---------------------+------------------------+
| user_id | msg_read | msg_time | msg_text |
+---------+--------------------+---------------------+------------------------+
| 72 | 2014-09-28 12:45:26| 2014-09-22 12:45:26 | Hello Andy from Mark |
| 106 | | 2015-04-18 12:47:04 | Hello Andy from Carol |
| 12388 | 2014-09-20 12:46:37| 2014-09-20 12:45:37 | Hello Andy from Graham |
+---------+--------------------+---------------------+------------------------+
获取最新消息虽然证明是棘手的。在过去,我只是将JOIN用于另一个子查询,但在尝试对此进行相同操作时,它(当然)无法识别t
表。
SELECT
t.user_id,
t.msg_read,
t.msg_time AS msg_time,
t.msg_text
FROM
(
(
SELECT
m.user_from AS user_id,
m.msg_time AS msg_time,
m.msg_text,
m.msg_read
FROM
messages m
WHERE
m.user_to = 1
)
UNION
(
SELECT
m.user_to AS user_id,
m.msg_time AS msg_time,
m.msg_text,
m.msg_read
FROM
messages m
WHERE
m.user_from = 1
)
) t
INNER JOIN (SELECT MAX(msg_time) AS msg_time, user_id FROM t GROUP BY user_id) t2 ON (t.user_id=t2.user_id AND t.msg_time=t2.msg_time)
GROUP BY user_id
Table 't' doesn't exist
我意识到我可以简单地加入另一个包含UNION的查询,但这似乎是一种效率很低的工作方式。
我也希望我可以创建一个临时表,但似乎主机提供商禁止这样做。
有没有人有任何建议?我很高兴考虑UNION概念的替代品。
作为参考,预期结果应为:
+---------+--------------------+---------------------+----------------------------+
| user_id | msg_read | msg_time | msg_text |
+---------+--------------------+---------------------+----------------------------+
| 106 | | 2015-04-18 12:47:04 | Hello Andy from Carol |
| 72 | | 2014-10-18 12:46:01 | Back to you Mark from Andy |
| 12388 | 2014-09-20 12:46:37| 2014-09-20 12:51:08 | Hello Graham from Andy |
+---------+--------------------+---------------------+----------------------------+
答案 0 :(得分:2)
首先,您不需要union
。以下查询获取所有消息:
SELECT (case when m.user_to = 1 then m.user_from else m.user_to end) AS user_id,
m.msg_time, m.msg_text, m.msg_read
FROM messages m
WHERE 1 in (m.user_to, m.user_from);
如果您想要每个用户使用最新的一个,只需使用聚合来获取最新消息并使用join
进行过滤:
SELECT m.*
FROM (SELECT (case when m.user_to = 1 then m.user_from else m.user_to end) AS user_id,
m.msg_time, m.msg_text, m.msg_read
FROM messages m
WHERE 1 in (m.user_to, m.user_from)
) m JOIN
(SELECT (case when m.user_to = 1 then m.user_from else m.user_to end) AS user_id,
MAX(m.msg_time) as maxt
FROM messages m
WHERE 1 in (m.user_to, m.user_from)
GROUP BY (case when m.user_to = 1 then m.user_from else m.user_to end)
) mm
ON m.user_id = mm.user_id and
m.msg_time = mm.maxt;