Come unire due tabelle per ottenere le righe mancanti nella seconda tabella


21

In un semplice sistema di voto come

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

per ottenere l'elenco delle elezioni votate da un utente, viene utilizzato il seguente JOIN

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

ma come ottenere l'elenco delle elezioni NON votato da un utente?

Risposte:


21

Utilizzare la query esistente per ottenere il contrario dell'elenco desiderato. Tale elenco può quindi essere verificato tramite NOT IN per ottenere l'elenco desiderato.

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

Utilizzare un join esterno:

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

L'ID utente sarà vuoto se non sono stati espressi voti per una determinata elezione, altrimenti verrà visualizzato

Se desideri elencare solo le elezioni in cui non vi sono voti espressi, potresti farlo in questo modo:

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

5

Ci sono molti modi per ottenere ciò che stai chiedendo. Forse il modo più semplice è usare un approccio puramente orientato al set:

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

Dal set di elezioni, rimuoviamo quelli in cui l'utente ha votato. Il risultato può essere unito alle elezioni per ottenere il titolo delle elezioni. Anche se non hai taggato la tua domanda, c'è motivo di credere che stai usando MySQL e MINUS o EXCEPT non sono supportati lì.

Un'altra variante è utilizzare il NOT EXISTSpredicato:

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

Cioè le elezioni in cui non esiste un voto da parte dell'utente. Il NOT INpredicato può essere utilizzato in modo simile. Dal momento che potrebbero esserci nulli, vale la pena notare che la semantica differisce tra IN ed EXISTS.

Infine, è possibile utilizzare un join esterno

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;

Se non ci sono righe che corrispondono al predicato ON, tutte le colonne dei voti vengono sostituite con null nel risultato. Pertanto, possiamo verificare se una colonna dei voti è nulla nella clausola WHERE. Poiché entrambe le colonne nei voti possono essere nulle, devi fare attenzione.

Idealmente, dovresti correggere i tuoi tavoli in modo da non dover affrontare i gotcha causati da 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
Poiché la risposta accettata ha attirato elezioni in cui un elettore specifico non ha votato, ciò non risponde alla domanda del PO. E, naturalmente, è solo una piccola modifica di una delle altre risposte, per ottenere elezioni in cui nessuno ha votato. Un commento in tal senso potrebbe far sembrare questa una risposta leggermente migliore. Tuttavia, dalla foto, abbastanza buono per una scimmia! :-)
RDFozz
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.