表A(列ID
和DESC
)和B(列FK_ID
,CODE
)之间存在一对多的关系。 ID
- > FK_ID
。
我很想找到效率最高的SQL来选择A中的所有行,其中B中的代码名为“C1”,但{B}中有NOT
个代码,名为“N1”。
任何帮助表示感谢。
答案 0 :(得分:3)
使用EXISTS
和NOT 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 join和semi 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')