我在从用户之间存储消息的表中检索数据时遇到问题。 这是表格:
CREATE TABLE messages
(
id INT UNSIGNED NOT NULL AUTO_INCREMENT,
sender VARCHAR(20),
recipient VARCHAR(30),
content TEXT,
is_read TINYINT(1),
created_at DATETIME,
PRIMARY KEY (`id`) ,
INDEX idx_sender (sender) ,
INDEX idx_recipient (recipient)
);
INSERT INTO messages (id, sender, recipient, content, is_read, created_at)
VALUES
-- Alice and George
(1, 'Alice', 'George', 'Happy new year', 1, '2012-12-24 23:05:00'),
(2, 'George', 'Alice', 'It is chrimas night...', 1, '2012-12-24 23:10:00'),
(3, 'Alice', 'George', 'Happy Xmas then', 0, '2012-12-25 00:00:00'),
-- John and Paul
(4, 'John', 'Paul', 'Hi Paul', 1, '2012-12-26 09:00:00'),
(5, 'Paul', 'John', 'Hi John', 1, '2012-12-26 09:05:00'),
(6, 'John', 'Paul', 'Have you done this ?', 1, '2012-12-26 09:10:00'),
(7, 'Paul', 'John', 'No I was unpacking my gifts', 0, '2012-12-26 09:05:00'),
-- George and Tim
(8, 'George', 'Tim', 'How was the end of the world ?', 1, '2012-12-22 10:10:00'),
(9, 'Tim', 'George', 'Really nice !', 0, '2012-12-22 10:15:00'),
-- John and Tim
(10, 'John', 'Tim', 'I don\'t know if I should fire you for new year\'s eve', 1, '2012-12-27 15:20:00'),
(11, 'Tim', 'John', 'That is a great idea!', 0, '2012-12-27 15:20:00');
假设George和John是经理,其他人是员工。 我需要检索管理者是收件人的最新未读邮件。 与此同时,我必须只检索那些也是对话发起者的消息。
所以结果必须是:
我做了一个几乎是查询的查询,但是消息ID 11的行丢失了:
SELECT
m.*
FROM
messages m
INNER JOIN (
-- retrieve the first message (fm)
SELECT t.sender, t.recipient
FROM (
SELECT id, sender, recipient, content, created_at,
IF ( sender IN ('John', 'George'), sender, recipient ) AS the_other
FROM messages
WHERE
sender IN ('John', 'George')
OR recipient IN ('John', 'George')
ORDER BY
created_at ASC
) t
GROUP BY
the_other
HAVING t.sender IN ('John', 'George')
) fm ON fm.recipient = m.sender
AND fm.sender = m.recipient
WHERE
m.recipient IN ('John', 'George')
AND m.is_read = 0
ORDER BY
m.created_at DESC
LIMIT 0, 10
缺少消息ID 11,因为子查询是由the_other分组的。 如果我将发件人和收件人分开“分组依据”,它将检索邮件ID 3,但这是一个不需要的行。
什么应该是解决我问题的SQL?
答案 0 :(得分:0)
可以使用以下查询:
select a.* from
(select id, sender, recipient, content, is_read, max(created_at)
from message where recipent in ('John', 'George') and is_read = 0
group by sender) a, message b (select id, sender, recipient,
content, is_read, min(created_at)
from message where sender in ('John', 'George') group by recipient) b
where a.sender=b.recepient
答案 1 :(得分:0)
最后我找到了一个解决方案,但我不认为这是最优化的查询:
SELECT
m.*
FROM
messages m
INNER JOIN (
-- retrieve the first messages (fm)
SELECT t.sender, t.recipient
FROM (
SELECT id, sender, recipient, content, created_at,
IF ( sender = 'John', recipient, sender ) AS the_other
FROM messages
WHERE
sender = 'John'
OR recipient = 'John'
ORDER BY
created_at ASC
) t
GROUP BY
the_other
HAVING t.sender = 'John'
UNION
SELECT t.sender, t.recipient
FROM (
SELECT id, sender, recipient, content, created_at,
IF ( sender = 'George', recipient, sender ) AS the_other
FROM messages
WHERE
sender = 'George'
OR recipient = 'George'
ORDER BY
created_at ASC
) t
GROUP BY
the_other
HAVING t.sender = 'George'
) fm ON fm.recipient = m.sender
AND fm.sender = m.recipient
WHERE
m.recipient IN ('John', 'George')
AND m.is_read = 0
ORDER BY
m.created_at DESC
LIMIT 0, 10