Как объединить две таблицы, чтобы получить пропущенные строки во второй таблице

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'

но как получить список выборов, за которые пользователь НЕ проголосовал?

Googlebot
источник

Ответы:

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'
)
Sparr
источник
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Предикат может быть использован аналогичным образом. Поскольку могут быть задействованы значения NULL, стоит отметить, что семантика отличается между 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, в результате все столбцы из голосов заменяются на ноль. Поэтому мы можем проверить, является ли какой-либо столбец из голосования нулевым в предложении WHERE. Поскольку оба столбца в голосах могут быть нулевыми, вам нужно быть осторожным.

В идеале вы должны исправить ваши таблицы, чтобы вам не приходилось иметь дело с ошибками, вызванными нулями:

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
Поскольку принятый ответ подтянул выборы, на которых конкретный избиратель не голосовал, это на самом деле не отвечает на вопрос ФП. И, конечно, это всего лишь незначительная настройка одного из других ответов, чтобы провести выборы, на которых никто не голосовал. Комментарий на этот счет может показаться немного лучшим ответом. Тем не менее, с картинки, довольно хорошо для обезьяны! :-)
RDFozz