我正在尝试根据特定条件从2个表中提取特定数据。但结果并不像预期的那样。有人可以帮忙吗?
标准: 需要获取类型为 A 的ID对。
表格:
表A
ID1 ID2
579643307310619501 644543316683180704
296151129721950503 328945291791563504
表B
ID TYPE
579643307310619501 A
579643307310619501 B
579643307310619501 C
644543316683180704 A
296151129721950503 A
328945291791563504 A
预期结果:
ID1 ID2
296151129721950503 328945291791563504
(因为只有这一对单独是A型)
注意:ID,ID1和ID2都必须出现在表B的ID字段中。
我尝试过的事情:
SELECT id1, id2
FROM A
JOIN B ON A.id1 = B.id
WHERE A.id1 IN (SELECT id FROM B)
AND A.id2 IN (SELECT id FROM B)
AND B.type='A'
GROUP BY id1, id2
HAVING count(*)=1;
答案 0 :(得分:1)
在下面的方法中,我使用CTE首先识别仅具有ID
类型的所有'A'
值。然后我将TableA
加入此CTE,两次,以过滤掉ID1
或ID2
值不属于'A'
的任何记录} type list。
WITH cte (ID) AS (
SELECT ID
FROM TableB
GROUP BY ID
HAVING SUM(CASE WHEN TYPE <> 'A' THEN 1 ELSE 0 END) = 0
)
SELECT a.ID1, a.ID2
FROM TableA a
INNER JOIN cte t1
ON a.ID1 = t1.ID
INNER JOIN cte t2
ON a.ID2 = t2.ID;
在下面找到一个工作演示(对于SQL Server - 我不能让Oracle在任何地方工作)。
答案 1 :(得分:1)
这是使用MINUS运算符的Oracle解决方案。
顶部子查询获取记录集,其中ID1和ID2都是'A'
类型。底部子查询获取记录集,其中ID1或ID2不是'A'
类型。结果是顶部集合中的记录集不在底部集合中。
select a.id1, a.id2
from a
join b b1 on b1.id = a.id1
join b b2 on b2.id = a.id2
where b1.type = 'A'
and b2.type = 'A'
minus
select a.id1, a.id2
from a
join b b1 on b1.id = a.id1
join b b2 on b2.id = a.id2
where b1.type != 'A'
or b2.type != 'A'
/
这个$slice会返回正确的行,但显示器有点问题:由于某种原因,数字会向下舍入。
关于表现的说明
这会两次点击表A
,并且表B
四次。使用小表和大小适中的缓冲区缓存,这并不是那么重要。
@TimBiegeleisen使用WITH子句,该方法只触及每个表一次。但是,Oracle将CTE实现为临时表。对于如此少量的数据执行此操作的开销使得他的解决方案始终比我的慢。在CTE预测中包含/*+ inline */
提示可防止Oracle实现临时表,并且两个查询的性能可比较。
但是,如果表变得足够大,那么使用具体化临时表的WITH子句方法将是一种更具表现性的方法。与查询调优一样,具体事项非常重要,基准测试是成功的关键。
答案 2 :(得分:1)
以下是Oracle和我的解决方案的示例。
这适用于任何字母A,B,C ...如果您只想要A,请在主查询的位置添加额外的过滤器。
create table a (id1 number,id2 number, constraint pk_a primary key(id1,id2));
create table b (id number, type char(1), constraint pk_b primary key(id,type));
insert into a values(57,64);
insert into a values(29,32);
insert into b values(57,'A');
insert into b values(57,'B');
insert into b values(57,'C');
insert into b values(64,'A');
insert into b values(29,'A');
insert into b values(32,'A');
commit;
select a.*
from a, b b1, b b2
where a.id1 = b1.id
and a.id2 = b2.id
and b1.type = b2.type
and not exists (select null
from b b1bis
where b1bis.id = b1.id
and b1.type <> b1bis.type)
and not exists (select null
from b b2bis
where b2bis.id = b2.id
and b2.type <> b2bis.type);