Як приєднатися до двох таблиць, щоб отримати пропущені рядки у другій таблиці


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

для отримання списку виборів, за який користувач проголосував, використовується наступне ПРИЄДНАННЯ

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

але як отримати список виборів, який користувач НЕ проголосував?

Відповіді:


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. Оскільки обидва стовпці голосів можуть бути недійсними, вам потрібно бути обережними.

В ідеалі вам слід виправити свої таблиці, щоб вам не доводилося мати справу з отриманими нулями:

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
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.