Jak dołączyć do dwóch tabel, aby uzyskać brakujące wiersze w drugiej tabeli

21

W prostym systemie głosowania jako

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

w celu uzyskania listy wyborów, które głosował użytkownik, zastosowano następujący DOŁĄCZ

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

ale jak uzyskać listę wyborów, których użytkownik NIE głosował?

Googlebot
źródło

Odpowiedzi:

21

Użyj istniejącego zapytania, aby uzyskać przeciwieństwo żądanej listy. Tę listę można następnie sprawdzić poprzez NOT IN, aby uzyskać żądaną listę.

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
źródło
17

Użyj sprzężenia zewnętrznego:

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 będzie pusty, jeśli na poszczególne wybory nie oddano głosów, w przeciwnym razie pojawi się

Jeśli chcesz tylko wymienić wybory, na których nie ma głosów oddanych, możesz to zrobić w następujący sposób:

select *
from elections e
where election_id NOT IN 
 (select election_id
  from votes
  where user_id = @userid
 )
druzin
źródło
5

Istnieje wiele sposobów na osiągnięcie tego, o co prosisz. Być może najprostszym sposobem jest zastosowanie podejścia zorientowanego na zestaw:

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

Z zestawu wyborów usuwamy te, w których głosował użytkownik. Wynik można połączyć z wyborami, aby uzyskać tytuł wyborów. Chociaż nie otagowałeś swojego pytania, istnieje powód, by sądzić, że używasz MySQL, a MINUS lub EXCEPT nie są tam obsługiwane.

Innym wariantem jest użycie NOT EXISTSpredykatu:

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 = ?
);

Tj. Wybory, w których nie istnieje, głosuje użytkownik. NOT INOrzecznik może być stosowane w podobny sposób. Ponieważ mogą występować wartości zerowe, warto zauważyć, że semantyka różni się pomiędzy IN i EXISTS.

Wreszcie możesz użyć sprzężenia zewnętrznego

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;

Jeśli nie ma wierszy pasujących do predykatu ON, wszystkie kolumny z głosów zostaną w wyniku zastąpione przez null. Możemy zatem sprawdzić, czy jakaś kolumna z głosów jest pusta w klauzuli WHERE. Ponieważ obie kolumny w głosowaniu mogą być zerowe, musisz zachować ostrożność.

Najlepiej jest naprawić tabele, aby nie musieć radzić sobie z problemami spowodowanymi przez wartości zerowe:

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)
);   
Lennart
źródło
-3
SELECT * 
FROM elections 
WHERE election_id NOT IN (
    SELECT DISTINCT(election_id) from votes
);
Dmitriy Grigoryan
źródło
4
Ponieważ przyjęta odpowiedź pociągnęła za sobą wybory, w których konkretny głosujący nie głosował, to tak naprawdę nie odpowiada na pytanie PO. I, oczywiście, to tylko drobna poprawka jednej z pozostałych odpowiedzi, aby uzyskać wybory, w których nikt nie głosował. Komentarz do tego efektu może sprawić, że będzie to nieco lepsza odpowiedź. Jednak z obrazka całkiem nieźle jak na małpę! :-)
RDFozz