2012-01-16 71 views
0

我在表A(列IDDESC)和B(列FK_ID,CODE)之间有一对多的关系。 ID - >FK_ID在连接表中选择值和非值的有效SQL

我很想知道如何找到最有效的SQL来选择A中的所有行,其中B中有一个名为'C1'的代码,但在名为'N1'的B中有NOT代码。

任何帮助表示赞赏。

+1

RDBMS是什么? SQL Server? MySQL的?甲骨文? – JNK 2012-01-16 18:22:57

回答

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') 
+0

+1 - 我认为这是最快的方法(假设为SQL Server) – JNK 2012-01-16 18:31:16

+0

+1,尽管它可能无法提供最佳性能 - 在某些数据库(包括MySQL中,我认为)左外连接与外连接处的NULL表可以提供更好的性能。 – 2012-01-16 18:33:49

+0

@MarkBannister for MySQL如果两边的列不能为空,那么左连接与空检查会更快,否则“存在”更好。对于SQL服务器“存在”总是更好(如果我没有记错的话)。 – Magnus 2012-01-16 18:44:17

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') 
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' 
      );