简体   繁体   中英

Select last distinct pair

Ok we have inbox table where we keep messages that users send to each other. Here is the table:

CREATE TABLE IF NOT EXISTS `inbox` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`fromid` int(10) unsigned NOT NULL DEFAULT '0',
`toid` int(10) DEFAULT NULL,
`message` text CHARACTER SET utf8 NOT NULL,
`time` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
PRIMARY KEY (`id`),
KEY `toid` (`toid`),
KEY `fromid` (`fromid`),
KEY `fromid_2` (`fromid`,`toid`)
) ENGINE=MyISAM  DEFAULT CHARSET=latin1  ;

fromid and toid are id's of the users. We have their id's, times when the message is sent. What we need is a query that would return all messages that are not replied by 'our users' (admins). Table accounts keeps track of users. To simplify:

CREATE TABLE IF NOT EXISTS `accounts` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`our` int(1) unsigned NOT NULL DEFAULT '0',
PRIMARY KEY (`id`)
) ENGINE=MyISAM  DEFAULT CHARSET=latin1;

So basically, we need a query that gives us the users WHOSE messages WERE NOT ANSWERED by admins (our users), their count and the date of the last message they sent to ADMIN, ordered from last to oldest.

So far we only have some basic queries, we didn't come up with anything reasonable that I could post.

Thanks in advance.

EDIT: From what I see we first need to find last interaction from two DISTINCT users in inbox table... then check & filter only those that were sent TO our users

How about this?

SELECT i.* FROM inbox as i 
WHERE (i.toid, i.fromid) NOT IN 
(SELECT i2.fromid, i2.toid FROM inbox as i2 WHERE i2.`time` >= i1.`time` AND i2.id = 1);

Another way using join :

SELECT DISTINCT i1.* 
FROM inbox as i1 LEFT JOIN inbox as i2 
    ON  i1.toid = 1 AND 
        i1.fromid = i2.toid AND 
        i1.toid = i2.fromid AND 
        i1.`time` <= i2.`time`
WHERE i2.id IS NULL;

Two possible solutions presented below: LEFT JOIN solution should perform better.

LEFT JOIN solution

SELECT 
 i.fromid, COUNT(*) AS unread, MAX(i.time) AS lastmsg 
FROM inbox AS i 
INNER JOIN accounts AS a 
 ON i.toid = a.id 
LEFT JOIN inbox AS i2 
 ON i.fromid = i2.toid AND i.toid = i2.fromid AND i.time <= i2.time 
WHERE a.our = 1 AND i2.id IS NULL
GROUP BY i.fromid
ORDER BY lastmsg DESC;

NOT IN solution

SELECT 
 i.fromid, COUNT(*) AS unread, MAX(i.time) AS lastmsg
FROM inbox AS i 
INNER JOIN accounts AS a ON i.toid = a.id 
WHERE a.our = 1 AND 
 (i.toid, i.fromid) 
 NOT IN (SELECT i2.fromid, i2.toid FROM inbox AS i2 WHERE i2.time >= i.time) 
GROUP BY i.fromid
ORDER BY lastmsg DESC;

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM