2017-02-10 74 views
3

我有两个SQL Server表:CHANNELS & SUBSCRIBERS,我想从CHANNELS行没有在SUBSCRIBERS一些条件存在。如何获取SQL中两个表中不匹配的行?

我试过INNEROUTER(LEFT) JOIN但它没有为我工作,他们都给了我同样的答案,这不是我想要的。

的表是这样的:

渠道表:

CREATE TABLE CHANNELS 
(
    ChanID INTEGER NOT NULL GENERATED ALWAYS AS IDENTITY (START WITH 1, INCREMENT BY 1) PRIMARY KEY, 
    name varchar(30) NOT NULL, 
    type varchar(10) NOT NULL, 
    description varchar(500) NOT NULL, 
    nickname varchar(20) NOT NULL 
      REFERENCES USERS(nickname), 
    subscribersnum int NOT NULL 
) 

SUBSCRIBERS表:

CREATE TABLE SUBSCRIBERS 
(
    nickname varchar(20) NOT NULL REFERENCES USERS(nickname), 
    ChanID int NOT NULL REFERENCES CHANNELS(ChanID) 
) 

外键nickname从一些所谓的其它表取USERS

比方说,在渠道我们有以下行:

CHanID | type | name | description | (createdby) | subscribersnum 
     |  |   |    | nickname | 
------------------------------------------------------------------------- 
    1  public first   hi   Matty   3 
    2  public second  hii   Rose   2 
    3  private third   hiii  Matty   2 
    4  public forth   hiiii  Lucy   5 

SUBSCRIBERS我们:

nickname | ChanID 
------------------------ 
    Jonny   1 
    Matty   3 
    Jonny   4 
    Rose   3 
    Rose   2 

我想选择所有公共通道的ID和具有昵称“Jonny”的用户尚未订阅的名称,因此在上面的示例中,我希望查询返回两行:

ChanId | name 
----------------- 

    2  second 

,我所做的查询是这样的:

SELECT 
    CHANNELS.ChanID 
FROM 
    CHANNELS 
LEFT JOIN 
    SUBSCRIBERS ON (CHANNELS.type = 'public' 
        AND SUBSCRIBERS.nickname = 'Jonny' 
        AND CHANNELS.ChanID != SUBSCRIBERS.ChanID); 

SELECT 
    CHANNELS.ChanID 
FROM 
    CHANNELS 
INNER JOIN 
    SUBSCRIBERS ON (CHANNELS.type = 'public' 
        AND SUBSCRIBERS.nickname = 'Jonny' 
        AND CHANNELS.ChanID != SUBSCRIBERS.ChanID); 

但他们没有做什么,我需要。

有什么建议吗?

谢谢

回答

2

如果您想知道是否存在记录,请使用[NOT] EXISTS[NOT] IN。您需要channels表中的数据,因此请从该表中选择并在条款WHERE中有条件。

select chanid, name 
from channels 
where type = 'public' 
and chanid not in (select chanid from subscribers where nickname = 'Jonny'); 
+0

这是完全很好,谢谢! – user6561572

1

你似乎混淆了与where条件的连接条件。 您的预期结果也有错误,第三个频道不应根据您之前的条件显示只有PUBLIC类型。

SELECT DISTINCT CHANNELS.ChanId, CHANNELS.name 
FROM CHANNELS 
JOIN SUBSCRIBERS on CHANNELS.ChanId = SUBSCRIBERS.ChanID 
WHERE CHANNELS.type = 'public' 
AND SUBSCRIBERS.nickname !='Jonny' 

这应该做的伎俩。

+2

不,这会让您获得其他人订阅的所有频道,无论Johnny是否订阅了这些频道。 –

+0

@PaulDaubian,感谢您通知我关于第三通道,我固定它,但是当我想你的代码,它给了我完全一样的Thorsten KETTNER说,任何方式感谢你,我可能需要此查询一些如何在我的工作 – user6561572

0

将风险旁人的言语中伤非测试,决然不是最高效解决方案,但想着这一些之后,我认为接近它是让所有的组合,则看到的最好的方式是哪些不是在用户列表:

select distinct a.nickname,b.chanid 
     from subscribers a 
    cross join 
    (select chanid 
     from channels 
    where type='public') b 
    left outer join subscribers c 
     on a.nickname=c.nickname 
    and b.chanid=c.chanid 
    where c.chanid is null 

的交叉连接给你所有可能的用户组合。那么,诀窍就是看看这些组合中是否存在这些组合中的每一个。这允许您在右侧使用外连接并测试null。再一次,也许不是完美或理想的解决方案,但我认为它会让你得到你需要的经验。同样,测试,但我相信这个想法是可行的。

1

你一直试图以应用反连接模式,这当您遇到性能问题与您通常使用的直进NOT EXISTSNOT IN(当DBMS优化并不能充分处理这些恰好)。

我展示了如何编写直接的查询。感谢您接受它:-)

为了完整起见,我告诉你,在这里如何构建反连接:防加入这样的作品,你外加入其他表,但后来关闭所有比赛在where子句中,从而保持不匹配。这可能会导致大量的中间结果,但往往仍执行快,因为加入是什么数据库管理系统就能做到最好(尤其是年轻DBMS不优化这么好)。

SELECT 
    CHANNELS.ChanID 
FROM 
    CHANNELS 
LEFT JOIN 
    SUBSCRIBERS ON SUBSCRIBERS.ChanID = CHANNELS.ChanID 
       AND SUBSCRIBERS.nickname = 'Jonny' 
WHERE 
    CHANNELS.type = 'public' 
AND 
    SUBSCRIBERS.ChanID IS NULL; -- keep only outer-joined records, i.e. non-matches 
+0

太感谢你了,我敢肯定,我会利用这个以后,真的谢谢:) – user6561572

相关问题