如何联接两个表以获取第二个表中缺少的行


21

在简单的投票系统中

CREATE TABLE elections (
election_id int(11) NOT NULL AUTO_INCREMENT,
title varchar(255),

CREATE TABLE votes (
election_id int(11),
user_id int(11),
FOREIGN KEYs

为了获得用户投票的选举列表,使用了以下JOIN

SELECT * FROM elections
JOIN votes USING(election_id)
WHERE votes.user_id='x'

但是如何获取用户未投票的选举列表?

Answers:


21

使用现有查询获取与所需列表相反的列表。然后可以通过NOT IN对照该列表,以获取所需列表。

SELECT * FROM elections WHERE election_id NOT IN (
    SELECT elections.election_id from elections
    JOIN votes USING(election_id)
    WHERE votes.user_id='x'
)

17

使用外部联接:

select e.election_id, e.title, v.user_id
from Elections e
 LEFT OUTER JOIN votes v ON v.election_id = e.election_id and v.user_id = @userid

如果没有为特定的选举投票,则UserId将为空,否则将显示

如果您只想列出没有任何投票的选举,则可以这样进行:

select *
from elections e
where election_id NOT IN 
 (select election_id
  from votes
  where user_id = @userid
 )

5

有很多方法可以实现您的要求。也许最直接的方法是使用纯面向集合的方法:

select election_id from elections
minus -- except is used instead of minus by some vendors
select election_id from votes where user_id = ?

从该组选举中,我们删除用户已投票的那些选举。结果可以与选举一起获得选举的标题。即使您没有标记问题,也有理由相信您正在使用MySQL,并且那里不支持MINUS或EXCEPT。

另一个变体是使用NOT EXISTS谓词:

select election_id, title 
from elections e
where not exists (
    select 1 
    from votes v
    where e.election_id = v.election_id
      and v.user_id = ?
);

即不存在来自用户的投票的选举。该NOT IN谓词可以以类似的方式被使用。由于可能涉及空值,因此值得注意的是IN和EXISTS之间的语义不同。

最后,您可以使用外部联接

select election_id, title 
from elections e
left join votes v
    on e.election_id = v.election_id
   and v.user_id = ?
where v.user_id is null;

如果没有与ON谓词匹配的行,则投票中的所有列将在结果中替换为null。因此,我们可以检查WHERE子句中投票的任何列是否为空。由于投票中的两列都可能为空,因此需要小心。

理想情况下,您应该修复表,这样就不必处理由null引起的问题:

CREATE TABLE elections 
( election_id int NOT NULL AUTO_INCREMENT PRIMARY KEY
, title varchar(255) not null );

CREATE TABLE votes 
( election_id int not null
, user_id int not null
,     constraint pk_votes primary key (election_id, user_id)
,     constraint fk_elections foreign key (election_id)
                              references elections (election_id)
);   

-3
SELECT * 
FROM elections 
WHERE election_id NOT IN (
    SELECT DISTINCT(election_id) from votes
);

4
由于公认的答案导致了特定选民不参加选举的选举,因此这并不能真正回答OP的问题。而且,当然,这只是对其他答案之一的细微调整,可以使没有人投票的选举得以实现。对此效果发表评论可能会使它看起来似乎是一个更好的答案。尽管如此,从图片上看,对猴子来说还不错!:-)
RDFozz
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.