这些是我的表格:
Class - id - name Order - id - name - class_id (FK) Family - id - order_id (FK) - name Genus - id - family_id (FK) - name Species - id - genus_id (FK) - name
我正在尝试进行查询以获取其下没有任何Species的Class,Order和Family名称列表.您可以看到该表具有从Order一直到Species的某种形式的层次结构.每个表都有外键(FK),它与层次结构上面的直接表相关.
试图让这个工作,但我做得不好.任何帮助,将不胜感激!
元答案(对前两个答案的评论):
使用IN往往会降级为非常类似于IN中所有项的OR(分离)的东西.表现不佳.
进行左连接并寻找null是一种改进,但它是蒙昧主义.如果我们可以说出我们的意思,那么就让我们用自然语言说出来的最糟糕的说法:
select f.name
from family f left join genus g on f.id = g.family_id
WHERE NOT EXISTS (select * from species c where c.id = g.id);
Run Code Online (Sandbox Code Playgroud)
我们想要什么东西不存在,所以如果我们可以说"哪里不存在"就更好了.而且,select *在子查询并不意味着它真的带回了一整排,所以它不是一个"优化"来代替select *用select 1,至少不会在任何现代RDBMS.
此外,如果一个家庭有许多属(并且在生物学中,大多数家庭都这样做),当我们关心的只是家庭时,我们将获得每行(家庭,属)一行.所以让我们每个家庭获得一行:
select DISTINCT f.name
from family f left join genus g on f.id = g.family_id
WHERE NOT EXISTS (select * from species c where c.id = g.id);
Run Code Online (Sandbox Code Playgroud)
这仍然不是最佳的.为什么?那么它符合OP的要求,因为它找到了"空"属,但它没有找到没有属,"空"家庭的家庭.我们也能做到吗?
select f.name
from family f
WHERE NOT EXISTS (
select * from genus g
join species c on c.id = g.id
where g.id = f.id);
Run Code Online (Sandbox Code Playgroud)
我们甚至可以摆脱不同的东西,因为我们不会把家庭与任何东西联系在一起.这是一个优化.
OP的评论:
这是一个非常清晰的解释.但是,我很好奇为什么使用IN或析取对性能有害.您能详细说明一下,还是指向一个我可以了解更多不同数据库操作的相对性能成本的资源?
这样想吧.假设SQL中没有IN运算符.你怎么假装IN?
通过一系列OR:
where foo in (1, 2, 3)
Run Code Online (Sandbox Code Playgroud)
相当于
where ( foo = 1 ) or ( foo = 2 ) or (foo = 3 )
Run Code Online (Sandbox Code Playgroud)
好吧,你说,但这仍然没有告诉我为什么这很糟糕.这很糟糕,因为通常没有合适的方法来使用密钥或索引进行查找.所以,你得到的是无论是)一个表扫描,其中每个析取(OR操作一个以列表谓语或元素),该行得到测试,直到测试结果为真或列表耗尽.或者b)你得到每个这些析取的表扫描.第二种情况(b)实际上可能更好,这就是为什么有时你会看到一个带有OR的选择转换为OR联合的每个分支的一个选择:
select * from table where x = 1 or x = 3 ;
select * from table where x = 1
union select * from table where x = 3 ;
Run Code Online (Sandbox Code Playgroud)
现在这并不是说你永远不能使用OR或IN列表.在某些情况下,查询优化器是足够聪明,把一个IN列表为加盟 - 你给了其他的答案是恰恰是这是最有可能的情况下.
但是,如果我们可以明确地将查询转换为连接,那么我们不必怀疑查询优化器是否是智能的.通常,连接是数据库最擅长的.
| 归档时间: |
|
| 查看次数: |
349 次 |
| 最近记录: |