2

我正在尝试为消息传递系统制定一个 SQL 查询,该查询将返回所有线程的列表,这些线程的状态为“OPEN”,并且其最后一条消息不是由某个组中的用户发布的。

查询中涉及的表有:

threads
-------
threadId
timestamp
subject
status
clientId

messages
--------
messageId
userId
messagebody
timestamp
threadId

users
-----
userId
username
groupId

当前查询是:

SELECT threadId, timestamp, subject, status, clientId 
FROM threads
WHERE status='OPEN' 
ORDER BY timestamp DESC

效果很好;但我现在有一个新要求 - 如果线程中的最后一条消息是由 agroupId为 1 的用户发布的,那么它不应该在结果集中。

包括我需要的信息很简单:

SELECT threadId, timestamp, subject, status, clientId 
FROM threads
INNER JOIN messages USING(threadId)
INNER JOIN users USING(userId)
WHERE status='OPEN' 
GROUP BY threadId
ORDER BY timestamp DESC

但此时我被卡住了,因为我不知道如何让查询根据特定组messages.userId中最高的线程来过滤掉线程。timestamp我已经查看了HAVING所有聚合函数,但似乎没有任何内容符合要求。

编辑

我可能不够清楚,所以我将尝试用一个例子来说明。

以下是一些示例数据:

线程

threadId | timestamp | subject | status | clientId
--------------------------------------------------
1        | 1         | One     | OPEN   | 1
2        | 10        | Two     | OPEN   | 4
3        | 26        | Three   | OPEN   | 19
4        | 198       | Four    | OPEN   | 100

消息

messageId | userId | messagebody | timestamp | threadId
-------------------------------------------------------
1         | 3      | Hello, World| 1         | 1
2         | 1      | Hello       | 3         | 1
3         | 1      | ^&%&6       | 10        | 2
4         | 2      | Test        | 12        | 2
5         | 4      | Hi mum      | 26        | 3
6         | 1      | More tests  | 100       | 4

用户

userId | username | groupId
---------------------------
1      | Gareth   | 1
2      | JimBob   | 2
3      | BillyBob | 2
4      | Bod      | 3

在此示例数据集线程 1 和 4 应从查询中删除,因为用户Gareth(组 1 的成员)是最后一个发布到它们的人(threadId 1 中的 messageId 2,threadId 4 中的 messageId 5)。所以结果集应该只有线程 2 和 3 的线程数据(threadId、timestamp、subject、status 和 clientId)。

我为此测试数据创建了一个SQLfiddle 。

谁能在这里指出我正确的方向?

4

2 回答 2

2

听起来你想要这个:

SELECT threadId, timestamp, subject, status, clientId 
FROM threads t
INNER JOIN messages m
  ON t.threadId = m.threadId
INNER JOIN users u
  ON m.userId = u.userId
  and u.groupId != 1  --placed the groupId filter here.
WHERE status='OPEN' 
GROUP BY threadId
ORDER BY timestamp DESC

编辑,这似乎给了你你需要的东西:

SELECT t.threadId, 
  t.timestamp, 
  t.subject, 
  t.status, 
  t.clientId
FROM threads t
INNER JOIN messages m
  ON t.threadId = m.threadId
INNER JOIN users u
  ON m.userId = u.userId
WHERE status='OPEN' 
  AND NOT EXISTS (select t1.threadid
                  FROM threads t1
                  INNER JOIN messages m
                    ON t1.threadId = m.threadId
                  INNER JOIN users u
                    ON m.userId = u.userId
                  where u.groupid = 1
                     and t.threadid = t1.threadid)
ORDER BY timestamp DESC

SQL Fiddle with Demo

于 2012-09-14T12:05:26.703 回答
1

添加LIMIT 1到您的查询中是否可以解决您的问题?

SELECT threadId, timestamp, subject, status, clientId  
FROM threads 
INNER JOIN messages USING(threadId) 
INNER JOIN users USING(userId) 
WHERE status='OPEN'  
GROUP BY threadId 
ORDER BY timestamp DESC 
LIMIT 1

或将 where 子句更改为

WHERE status='OPEN' and groupID<>1

我想这就是你想要的?

select * from threads
where threadId not in
(
    select messages.threadId
    from messages
        inner join (select threadId, MAX(timestamp) maxtime from messages group by threadId) t
            on messages.threadId = t.threadId
            and messages.timestamp = t.maxtime
    where messages.userId=1
)   
于 2012-09-14T12:03:32.860 回答