以下使用x、y和z代替主题id,因为没有提供示例。
使用 JOIN:
SELECT m.*
FROM MESSAGES m
JOIN MESSAGETOPICRELATIONS mtr ON mtr.messageid = m.messageid
JOIN TOPICS tx ON tx.topicid = mtr.topicid
AND tx.topicid = x
JOIN TOPICS ty ON ty.topicid = mtr.topicid
AND ty.topicid = y
JOIN TOPICS tz ON tz.topicid = mtr.topicid
AND tz.topicid = z
使用 GROUP BY/HAVING COUNT(*):
SELECT m.*
FROM MESSAGES m
JOIN MESSAGETOPICRELATIONS mtr ON mtr.messageid = m.messageid
JOIN TOPICS t ON t.topicid = mtr.topicid
WHERE t.topicid IN (x, y, z)
GROUP BY m.messageid, m.messagetext
HAVING COUNT(*) = 3
在这两者中,JOIN 方法更安全。
GROUP BY/HAVING 依赖于 MESSAGETOPICRELATIONS.TOPICID 作为主键的一部分,或者具有唯一键约束以确保没有重复项。否则,您可能会将同一主题的 2 个以上实例关联到一条消息 - 这将是误报。使用HAVING COUNT(DISTINCT ... 会清除任何误报,但支持取决于数据库 - MySQL 在 5.1+ 时支持它,但在 4.1 时不支持。 Oracle 可能要等到星期一才能在 SQL Server 上进行测试...
我查看了 Bill 关于不需要加入 TOPICS 表的评论:
SELECT m.*
FROM MESSAGES m
JOIN MESSAGETOPICRELATIONS mtr ON mtr.messageid = m.messageid
AND mtr.topicid IN (x, y, z)
...将返回误报 - 至少匹配 IN 子句中定义的值之一的行。并且:
SELECT m.*
FROM MESSAGES m
JOIN MESSAGETOPICRELATIONS mtr ON mtr.messageid = m.messageid
AND mtr.topicid = x
AND mtr.topicid = y
AND mtr.topicid = z
...根本不会返回任何内容,因为 topicid 永远不可能同时包含所有值。