2017-04-26 90 views
0

对于简单表格,使用“left join”和“is null”替换“Not In”应该很容易。但是,就我而言,这并不那么简单。使用“左连接”替换特殊情况下的“不在”子句的SQL语句

这里是表A(项目,ReferenceID)

Item(primary key) ReferenceID 
Chair     123 
Desk     456 
Sofa     789 
Bed     111 

这里是tableB的(STOREID,ReferenceID)

StoreID(primary key) ReferenceID(primary key)  
00001     123       
00001     456       
00002     123  
00002     456  
00003     111 

注:表B是表示被排除在哪些项目表哪个商店。 因此storeID = 00001具有除主席(参考ID = 123)和桌面(参考ID = 456)以外的所有项目。

给定一个StoreID = 00001,我怎么能写一个sql语句来达到这个目的。更具体地说,结果表应该是:

Item(primary key) ReferenceID 
Sofa     789 
Bed     111 

使用“Not-in”方法,其工作正常但缓慢。

select * from tableA 
    where ReferenceID not in (select ReferenceID from tableB where storeID='00001' 

现在我试图不使用“不在”子句,因为性能低下。 我尝试使用“左连接”,但它似乎并没有返回我想要的。

#1。

select * from tableA left join tableB 
    on tableA.referenceID = tableB.referenceID 
where tableB.StoreID is null 

,因为它TableB中

存在

#2这种方法就可以排除(床,111)。尝试添加storeID来过滤结果。

select * from tableA left join tableB 
     on (tableA.referenceID = tableB.referenceID and StoreID='00001') 
where tableB.StoreID is null 

结果集与排除(bed,111)的#1中的方法相同。

问题:

什么是正确的SQL语句来达到这个目的?

只要性能比使用“不在”条款更好,我也可以接受其他不使用“左连接”的方法。

编辑:

我简化了实际的SQL语句和上面的助手更容易明白我想实现的情况,因为我想跳过额外的表和SQL语句并不重要。

根据以下评论,我认为现在很重要,因为#2方法似乎在上述简化情况下正常工作。因此,我必须再添加一张表来重现我所遇到的实际问题。

其实还有一张表。我加入tableA和tableC,然后离开join tableB。

表C(项目,itemDescrption)

Item(primary key) itemDescrption 
    Chair     Very comfortable. 
    Desk     broken 
    sofa     large sofa (24*12) 
    bed     double size 

至于上面的方法#2,实际的说法是

select * from tableA 
    inner join tableC on tableA.item = tableC.item 
    left join tableB 
     on (tableA.referenceID = tableB.referenceID and StoreID='00001') 
where tableB.StoreID is null 
+0

2号除了'床'怎么样? – JNevill

+0

(1)如果商店不会遗漏任何商品,那么它不会出现在报告中。你需要一个有商店的桌子。 (2)像这样的语法操作几乎不是实现性能的好路径 –

+0

因为我以为我生气了,所以我在我的盒子上创建了'tableA'和'tableB'并运行了第二个查询。它工作正常。 – JNevill

回答

0

我相信你的第二次尝试是正确的方式去(虽然,我认为NOT IN并没有那么糟糕,但如果这是更快然后我所有的话):

mysql> SELECT * FROM tableA; 
+-------+-------------+ 
| item | ReferenceID | 
+-------+-------------+ 
| Chair |   123 | 
| Desk |   456 | 
| Sofa |   789 | 
| Bed |   111 | 
+-------+-------------+ 
4 rows in set (0.00 sec) 

mysql> SELECT * FROM tableB; 
+---------+-------------+ 
| storeid | ReferenceID | 
+---------+-------------+ 
| 1  |   123 | 
| 1  |   456 | 
| 2  |   123 | 
| 2  |   456 | 
| 3  |   111 | 
+---------+-------------+ 
5 rows in set (0.00 sec) 

mysql> select * from tableA left join tableB on (tableA.referenceID = tableB.referenceID and StoreID='1') where tableB.StoreID is null; 
+------+-------------+---------+-------------+ 
| item | ReferenceID | storeid | ReferenceID | 
+------+-------------+---------+-------------+ 
| Sofa |   789 | NULL |  NULL | 
| Bed |   111 | NULL |  NULL | 
+------+-------------+---------+-------------+ 
2 rows in set (0.00 sec) 

更新了表C列入(这对结果没有任何影响s仍然按预期工作):

mysql> select * from tableA inner join tableC ON tableA.item = tableC.item left join tableB on (tableA.referenceID = tableB.referenceID and StoreID='1') where tableB.StoreID is null; 
+------+-------------+------+--------------------+---------+-------------+ 
| item | ReferenceID | item | ReferenceID  | storeid | ReferenceID | 
+------+-------------+------+--------------------+---------+-------------+ 
| Sofa |   789 | sofa | large sofa (24*12) | NULL |  NULL | 
| Bed |   111 | bed | double size  | NULL |  NULL | 
+------+-------------+------+--------------------+---------+-------------+ 
2 rows in set (0.00 sec) 
+0

有人在这里疯狂和低估了每个人。我赞成你。顺便说一句,如你所说,似乎#2方法是正确的。我想我搞砸了我的测试。 – Joey

+0

我希望你弄清楚是什么引起了这个问题。我有很多虚假的互联网点,所以我从downvote得到的-2不会伤害......;) – JNevill

0

你必须cross join与购买商店,然后left join对这个结果。

select a.item,a.referenceID 
from tableA a 
cross join (select distinct storeId from tableB) s 
left join tableB b on b.referenceID=a.referenceID and b.storeId=s.storeId 
where s.storeId='00001' and b.referenceID is null 
+0

为什么在单个INNER JOIN工作时使用CROSS JOIN + LEFT JOIN? –

+1

downvoter ..你能解释一下原因吗? –

+0

我认为有人生气并且低估了一切。根据op的规范,您可以提供备用数据来生成数据。我认为他们会有几个选项来运行过去的EXPLAIN。 – JNevill

2

改为不要存在。

SELECT * 
    FROM tableA tA 
    WHERE NOT EXISTS(SELECT 1 
         FROM tableB tB 
         WHERE tB.ReferenceID = tA.ReferenceID 
          AND tB.storeID = '00001'); 
+2

这通常是使用性能最高的代码。 – HLGEM

-1

由于店铺ID,这应该是您查询:

select a.* 
from tableA A 
INNER JOIN TableB B 
    ON A.ReferenceID = B.ReferenceID 
where A.storeID='00001' 
+0

它看起来不正确。顺便说一句,我没有投票你的答案。其他人做了。 – Joey

+1

我低估了它,因为它不正确。 'tableB'中的'referenceID'是不应包含在特定商店中的商品。当适当的回报将是“沙发”和“床”时,该查询将返回“主席”和“桌子”。 – JNevill