是否有更有效的方法来编写此SQL查询以删除不同的?

时间:2012-09-10 19:17:17

标签: sql sqlite join

我正在尝试从表A中选择项目,其中表B中的等价项目存在给定约束。表A中每个id有一行,但每个表A行有很多行。

select distinct A.id 
from A inner join B on B.a_id = A.id 
where B.x >= 5 and B.x <= 10;

我想知道是否有一个SQL连接子句可用于确保每个表A行只能获得一行。

据我了解,查询将找到约束,执行内连接,然后对此执行不同。如果这是正确的,并且有一种更好的方法来指示数据库只从A中获取不同的行,我想知道。我确信有很多方法可以在查询语义的约束下解释和执行查询。我不能声称理解explain输出。

有没有办法简化这个?如果这有任何区别,我会受限于SQLite。

修改

约束子句有两个约束,在我现在添加的查询时定义。我尽量保持这个问题尽可能简单,但为了回应评论而添加了额外的完整性条款。

2 个答案:

答案 0 :(得分:3)

以下是编写查询的另一种方法:

select A.id
from A
where A.id in (select B.a_id from B where B.x > 5)

我认为表现不会更好,但它确实消除了外在的“不同”。

我还会在MySQL中使用另一个版本:

select A.id
from A
where exists (select 1 from B where b.x > 5 and b.a_id = a.id limit 1)

这可能更有效,因为查询可以使用索引查找并在第一次匹配时停止。如果(a_id,x)的B上有索引,则尤其如此。

答案 1 :(得分:1)

如果两个表之间存在(正确执行)FOREIGN KEY,则通过删除表A可以获得(轻微)效率增益:

SELECT DISTINCT a_id AS id
FROM B 
WHERE x >= 5 and x <= 10 ;

(a_id, x)上的索引似乎合适,但效率取决于各种参数(ids的百分比与条件x>5匹配?有多少行具有相同的ID?等等。)

我也会尝试这个查询(在添加上面的索引之后):

SELECT a_id AS id
FROM B 
GROUP BY a_id
HAVING MAX(x) >= 5 
   AND MIN(x) <= 10 ;

当您需要来自A的数据时,这将有效:

SELECT A.* 
FROM A
  JOIN 
    ( SELECT a_id
      FROM B 
      GROUP BY a_id
      HAVING MAX(x) >= 5 
         AND MIN(x) <= 10  
    ) AS b
  ON b.a_id = a.id ;
相关问题