SELECT id,name,color
FROM animals a
INNER JOIN animal_tags atags ON atags.animal_id = a.id
WHERE atags.tag_id = 70 OR a.id IN (
SELECT a2.id FROM animals a2
WHERE a2.inherit_tags = 1 AND a2.species IN
(SELECT species.id FROM species
INNER JOIN species_tags stags ON stags.species_id = species.id
WHERE stags.tag_id = 70))
基本上,我正在寻找任何与tag_id 70(比如说“Fur”)有关联的动物和属于与tag_id 70关联的物种的任何动物,并且该动物应该继承其标签物种。
我的另一个选择是基本上删除继承标签片段,只是总是为动物定义标签......但不知何故,这似乎没有很正常化。 (请注意,* _tags表只包含关系,每个tag_id都与“tags”表关联,其中存储了标记详细信息。这对此查询并不重要,只是为了向您显示我的表模式已完全规范化。)
答案 0 :(得分:2)
我相信这个查询应该是等价的。
SELECT id, name, color
FROM animals a
INNER JOIN animal_tags atags
ON a.id = atags.animal_id
LEFT JOIN species s
INNER JOIN species_tags stags
ON s.id = stags.species_id
AND stags.tag_id = 70
ON a.species = s.id
AND a.inherit_tags = 1
WHERE atags.tag_id = 70
OR s.id IS NOT NULL
答案 1 :(得分:2)
由于您实际上不需要结果集中的标记表中的值,因此不需要完整的连接。通常,查询优化器可以使用exists
更有效地处理半连接。
此外,当物种表不必要时,您将加入中间表(动物 - 物种 - 种类标签),因为您所有三个表都加入了species_id。你可以绕过物种,从动物到物种标签。
最后,由于您已经在使用animals表并且正在评估OR条件,因此无需将该表连接到自身。这应该证明更有效。我还要确保你在tag_id,species_id等上有索引。
SELECT id, name, color
FROM animals a
WHERE EXISTS(SELECT 1
FROM animal_tags atags
where atags.tag_id = 70
and atags.animal_id = a.id)
OR (a.inherit_tags = 1
AND EXISTS( SELECT 1 from species_tags stags
WHERE stags.species_id = a.species
AND stags.tag_id = 70
)
)