“选择......在哪里”和加入的平等

时间:2011-08-24 11:45:57

标签: sql oracle join sql-in semi-join

假设我有table1这样:

id | itemcode
-------------
1  | c1
2  | c2
...

这样table2

item | name
-----------
c1   | acme
c2   | foo
...

以下两个查询是否会在每个条件下返回相同的结果集?

SELECT id, itemcode 
FROM table1 
WHERE itemcode IN (SELECT DISTINCT item 
                  FROM table2 
                  WHERE name [some arbitrary test])

SELECT id, itemcode 
FROM table1 
   JOIN (SELECT DISTINCT item 
          FROM table2
          WHERE name [some arbitrary test]) items 
         ON table1.itemcode = items.item

除非我真的错过了一些愚蠢的东西,否则我会说是的。但是我已经完成了两个问题,归结为这种形式,我得到了不同的结果。有一些使用WHERE IN的嵌套查询,但是在最后一步我注意到JOIN要快得多。嵌套查询都是完全孤立的,所以我不相信它们是问题,所以我只想消除我对上述内容产生误解的可能性。

感谢您的任何见解。

编辑

两个原始查询:

SELECT imitm, imlitm, imglpt 
    FROM jdedata.F4101 
    WHERE imitm IN 
  (SELECT DISTINCT ivitm AS itemno 
       FROM jdedata.F4104 
       WHERE ivcitm IN 
    (SELECT DISTINCT ivcitm AS legacycode 
             FROM jdedata.F4104 
              WHERE ivitm IN 
      (SELECT DISTINCT tritm 
               FROM trigdata.F4101_TRIG)
    )
  )


SELECT orig.imitm, orig.imlitm, orig.imglpt 
    FROM jdedata.F4101 orig 
        JOIN 
        (SELECT DISTINCT ivitm AS itemno 
        FROM jdedata.F4104 
        WHERE ivcitm IN 
              (SELECT DISTINCT ivcitm AS legacycode 
              FROM jdedata.F4104
               WHERE ivitm IN 
                 (SELECT DISTINCT tritm 
                  FROM trigdata.F4101_TRIG))) itemns 
ON orig.imitm = itemns.itemno

编辑2

虽然我仍然不明白为什么查询会返回不同的结果,但由于我们在某些部分使用了错误的列,因此我们的逻辑似乎从一开始就存在缺陷。请注意,我并没有说我错误地解释了上面写的查询或者有一些错字,我们只需要选择一些不同的东西。

通常情况下,我不会休息,直到我到达这些事情的底部,但我已经非常疲惫,并且从1月开始进入我的第一个假期超过一天,所以我不能真的被困扰搜索现在进一步。我相信这里给出的提示将在以后派上用场。已经分发了所有帮助的Upvotes,我接受了Ypercube的回答,主要是因为他的评论让我走得最远。但是全心全意!如果我稍后会发现更多内容,我会尽量记住ping回来。

5 个答案:

答案 0 :(得分:4)

由于table2.item不可为空,因此2个版本是等效的。您可以从distinct版本中删除IN,但这不是必需的。您可以查看这3个版本及其执行计划:

SELECT id, itemcode FROM table1 WHERE itemcode IN
  ( SELECT item FROM table2 WHERE name [some arbitrary test] )

SELECT id, itemcode FROM table1 JOIN
  ( SELECT DISTINCT item FROM table2 WHERE name [some arbitrary test] )
  items ON table1.itemcode = items.item

SELECT id, itemcode FROM table1 WHERE EXISTS
  ( SELECT * FROM table2 WHERE table1.itemcode = table2.item 
                           AND (name [some arbitrary test]) )

答案 1 :(得分:1)

理想情况下,我希望看到结果集之间的差异 - 你是否正在重复记录
- 一组总是另一组的子集 - 与另一组相比,一组是否具有“额外”和“缺失”记录?

那就是说,逻辑应该是等价的。我最好的猜测是你有一些空的字符串条目;因为Oracle的NULL CHAR / VARCHAR版本只是一个空字符串。如果您没有为此做好准备,这可以给出非常时髦的结果。

答案 2 :(得分:1)

两个查询都执行semijoin,即table2中没有属性出现在最顶层SELECT(结果集)中。

在我看来,您的第一个查询最容易识别为半连接,EXISTS更是如此。另一方面,优化器无疑会以不同的方式看待它;)

答案 3 :(得分:1)

您也可以尝试直接加入第二个表

SELECT DISTINCT id, itemcode 
FROM table1 
INNER JOIN table2 ON table1.itemcode = table2.item   
WHERE name [some arbitrary test] )

如果项目是主键或唯一,则您不需要 不同

存在 内部加入 应具有相同的执行速度,而 IN 更贵。

答案 4 :(得分:1)

我会在那里寻找一些数据类型转换。

create table t_vc (val varchar2(6));
create table t_c (val char(6));

insert into t_vc values ('12345');
insert into t_vc values ('12345 ');

insert into t_c values ('12345');
insert into t_c values ('12345');

select t_c.val||':'
from t_c
where val in (select distinct val from t_vc);

select c.val||':'
from t_vc v join (select distinct val from t_c) c on v.val=c.val;