我在MySQL:
我有2个表,一个是主表,另一个是附件表,其中包含一些支持主表记录的信息。
示例:
表门户网站:
id title desc
12 "aaa" "desc"
13 "bbb" "desc"
[etc]
辅助表(省略主要id字段)
type portalid
x 12
2 12
3 12
4 12
5 12
1 13
2 13
4 13
我需要选择表门户中的每条记录,这些记录在次表中获得了类型= 4但是!= 5的记录。
示例:
SELECT *
FROM portal,secondary_table s
WHERE portal.id=s.portalid
AND type of secondary_table is 4 and is not 5
结果:
在这种情况下,只返回门户网站的记录13,因为记录12同时包含类型4和5。
请注意我问了一个类似的问题,但只考虑了一个表格,并且该查询需要花费超过50秒才能详细说明。
感谢您的帮助
答案 0 :(得分:2)
您应该考虑使用NOT EXISTS条款对其进行重新措辞。如果您想要的只是来自portal
的记录,那么双EXISTS子句将起作用并且非常清楚地显示查询意图
SELECT *
FROM portal
WHERE EXISTS (select * from secondary_table s1
where portal.id=s1.portalid
and s1.type=4)
AND NOT EXISTS (select * from secondary_table s2
where portal.id=s2.portalid
and s2.type=5)
但是,由于MySQL处理EXISTS子句的方式(即使它更清楚),您可以使用LEFT JOIN / IS NULL来权衡澄清性能。请阅读以下链接,但每个查询的性能可能因特定数据分布而异,因此请尝试使用两者并使用更适合您数据的方式。
NOT IN vs. NOT EXISTS vs. LEFT JOIN / IS NULL: MySQL
将写入LEFT JOIN / IS NULL表单
SELECT *
FROM portal
JOIN secondary_table s1 ON portal.id=s1.portalid and s1.type=4
LEFT JOIN secondary_table s2 ON portal.id=s2.portalid and s2.type=5
WHERE s2.portalid IS NULL
表(portal,inner,left)的顺序是允许处理前两个表(portal + secondary / type = 4)并在启动到LEFT(外部)JOIN之前提前修剪结果集(保留对于存在性测试,从左侧开始的一切。
答案 1 :(得分:1)
这就是为什么你应该避免旧的FROM A,B
语法 - 它在某些方面不那么强大。使用显式连接类型(LEFT / RIGHT / INNER / FULL / CROSS)。
SELECT <columns>
FROM portal p
LEFT JOIN secondary s1 ON p.id=s1.portalid AND s1.type = 5
INNER JOIN secondary s2 ON p.id=s2.portalid AND s2.type = 4
WHERE s1.type IS NULL
答案 2 :(得分:0)
我将使用与richard的EXISTS非常相似的查询:
SELECT * FROM portal
WHERE id IN (SELECT portalid FROM sec WHERE type=4)
AND id NOT IN (SELECT portalid FROM sec WHERE type=5)
imo它更具可读性。