用于在连接表中选择值和NOT值的高效SQL

时间:2012-01-16 18:17:42

标签: sql performance select

表A(列IDDESC)和B(列FK_IDCODE)之间存在一对多的关系。 ID - > FK_ID

我很想找到效率最高的SQL来选择A中的所有行,其中B中的代码名为“C1”,但{B}中有NOT个代码,名为“N1”。

任何帮助表示感谢。

3 个答案:

答案 0 :(得分:3)

使用EXISTSNOT EXISTS可以获得最佳效果

SELECT tableA.*
FROM tableA
WHERE
  EXISTS(
    SELECT NULL
    FROM TableB 
    WHERE tableA.ID = TableB.FK_ID AND TableB.Code = 'C1')
  AND NOT EXISTS(
    SELECT NULL
    FROM TableB 
    WHERE tableA.ID = TableB.FK_ID AND TableB.Code = 'N1')

答案 1 :(得分:1)

  

选择A中的所有行,其中B中的代码名为“C1”,但B中没有名为“N1”的代码。

我怀疑你的规范没有准确地传达你实际需要的东西!

字面解释是

if there exists a row in B where CODE = 'C1'
   and there does not exist a row in B where CODE = 'B1'
then return all rows from A

(也就是说,A和B中的值之间没有相关性) 例如

SELECT * 
  FROM A
 WHERE EXISTS (
               SELECT * 
                 FROM B
                WHERE CODE = 'B1'
              )
       AND NOT EXISTS (
                       SELECT * 
                         FROM B
                        WHERE CODE = 'C1'
                      );

但是,经验(单独)告诉我们您可能希望使用A.ID = B.FK_ID关联表。请参阅Magnus对一种方法的回答。

注意这里提到的存在主义和非存在主义运算符分别称为semi joinsemi difference,它们可以用不同的方式在SQL中编写。从性能的角度来看哪个最有效将取决于许多变量,包括SQL引擎,数据,索引,统计等。您将需要使用典型数据进行测试。还要考虑可读性和易维护性也是重要因素。

如果您选择的SQL产品支持减运算符EXCEPT(在Oracle中实际称为MINUS),那么这个候选查询(或类似的东西)可能值得考虑:

SELECT * 
  FROM A
 WHERE ID IN (
              SELECT FK_ID
                FROM B
               WHERE CODE = 'B1'
              EXCEPT
              SELECT FK_ID 
                FROM B
               WHERE CODE = 'C1'
             );

答案 2 :(得分:0)

我的理解(如果我错了请纠正我)你有两张桌子如下:

create table A(ID int not null primary key, "DESC" varchar(30));
create table B(FK_ID int not null references A (ID), CODE varchar(30));

然后这样的事情会起作用:

select
    ta.* 
from
    A as ta
inner join
    B as tb
    on tb.FK_ID = ta.ID
where 
    tb.CODE = 'C1'
    and not exists (select null from B as tb2 where tb2.FK_ID = ta.ID and tb2.CODE = 'N1')