2013-01-25 11 views
5

Ho un database in cui le persone inviano voti per persone in posti diversi. In un dato momento, voglio scoprire chi ha il maggior numero di voti in ogni luogo. (Una persona può essere votato in due posti diversi)Come ottenere la riga massima di ogni gruppo?

Questa è la SQL che ho finora:

SELECT placeId, userVotedId, cnt 
FROM 
    (SELECT uvo.userVotedId, p.placeId, count(*) as cnt 
    FROM users as u, users_votes as uvo, places as p 
    WHERE u.userId = uvo.userVotedId 
     AND p.placeId = uvo.placeId 
    GROUP BY userVotedId, placeId) 
AS RESULT 

che mi dà questo risultato:

enter image description here

Ora, questi sono le righe voglio veramente:

enter image description here

Cosa manca nella mia query in modo che possa ottenere questo?

  • Voglio un risultato per posto. Quindi dovrei vedere solo placeIs distinti, con userVotedId che ha ricevuto il maggior numero di voti.

  • In caso di pareggio, un vincitore casuale farà!

+0

quello che si ottiene e quello che vuoi sono identici. Quindi, la tua query funziona! – cha

+0

@cha ho pensato la stessa, ma il punto è quello di eliminare la doppia placeid = 51. Ci potrebbero essere stati modi più afferrabili per segnalo questo invece delle quattro caselle rosse sconnesse ;-) – KekuSemau

+0

Se si sta tentando di ottenere il top riga basata su cnt una volta che hai ulteriormente raggruppato per placeID dei tuoi risultati, questo è un problema più difficile di quello a prima vista. In SQL Server penso che sia possibile farlo con APPLY, ma questo non è supportato (?) In MySQL. – Matthew

risposta

3

Sembra che avete bisogno di uno più aggregato. Utilizzare il MAX() complessivo sul valore cnt e GROUP BY placeId, userVotedId:

SELECT placeId, userVotedId, max(cnt) 
FROM 
(
    SELECT uvo.userVotedId, p.placeId, count(*) as cnt 
    FROM users as u 
    INNER JOIN users_votes as uvo 
    ON u.userId = uvo.userVotedId 
    INNER JOIN places as p 
    ON p.placeId = uvo.placeId 
    GROUP BY userVotedId, placeId 
) AS RESULT 
GROUP BY placeId, userVotedId 

Nota: ho cambiato la query per utilizzare la sintassi JOIN posto delle virgole tra i tavoli.

Edit, in base al commento seguente dovrebbe funzionare:

select total.uservotedid, 
    total.placeid, 
    total.cnt 
from 
(
    SELECT uvo.userVotedId, p.placeId, count(*) as cnt 
    FROM users as u 
    INNER JOIN users_votes as uvo 
    ON u.userId = uvo.userVotedId 
    INNER JOIN places as p 
    ON p.placeId = uvo.placeId 
    GROUP BY userVotedId, placeId 
) total 
inner join 
(
    select max(cnt) Mx, placeid 
    from 
    (
    SELECT uvo.userVotedId, p.placeId, count(*) as cnt 
    FROM users as u 
    INNER JOIN users_votes as uvo 
     ON u.userId = uvo.userVotedId 
    INNER JOIN places as p 
     ON p.placeId = uvo.placeId 
    GROUP BY userVotedId, placeId 
) mx 
    group by placeid 
) src 
    on total.placeid = src.placeid 
    and total.cnt = src.mx 

Vedi SQL Fiddle with Demo

Il risultato è:

| USERVOTEDID | PLACEID | CNT | 
------------------------------- 
|   65 |  11 | 1 | 
|   67 |  13 | 1 | 
|   67 |  25 | 1 | 
|   67 |  51 | 2 | 

Modifica # 2, se si desidera un numero casuale restituito se c'è un pareggio, quindi è possibile utilizzare le variabili utente:

select uservotedid, 
    placeid, 
    cnt 
from 
(
    select total.uservotedid, 
    total.placeid, 
    total.cnt, 
    @rownum := case when @prev = total.placeid then @rownum+1 else 1 end rownum, 
    @prev := total.placeid pplaceid 
    from 
    (
    SELECT uvo.userVotedId, p.placeId, count(*) as cnt 
    FROM users as u 
    INNER JOIN users_votes as uvo 
     ON u.userId = uvo.userVotedId 
    INNER JOIN places as p 
     ON p.placeId = uvo.placeId 
    GROUP BY userVotedId, placeId 
) total 
    inner join 
    (
    select max(cnt) Mx, placeid 
    from 
    (
     SELECT uvo.userVotedId, p.placeId, count(*) as cnt 
     FROM users as u 
     INNER JOIN users_votes as uvo 
     ON u.userId = uvo.userVotedId 
     INNER JOIN places as p 
     ON p.placeId = uvo.placeId 
     GROUP BY userVotedId, placeId 
    ) mx 
    group by placeid 
) src 
    on total.placeid = src.placeid 
    and total.cnt = src.mx 
    order by total.placeid, total.uservotedid 
) src 
where rownum = 1 
order by placeid, uservotedid 

Vedi SQL Fiddle with Demo

+0

no ... non funziona: http://imgur.com/8cpl8pO –

+0

Vuoi il massimo da un solo posto? O vuoi anche l'ID utente? – Taryn

+0

Voglio un risultato per posto. Quindi dovrei vedere solo placeIs distinti, con userVotedId che ha ricevuto il maggior numero di voti. –

1
SELECT placeId, userVotedId, MAX(cnt) 
    FROM (SELECT uvo.userVotedId, p.placeId, count(*) AS cnt 
      FROM users as u, users_votes as uvo, places as p 
      WHERE u.userId = uvo.userVotedId AND p.placeId = uvo.placeId 
      GROUP BY userVotedId, placeId) AS RESULT 
    GROUP BY placeId 
+0

questo restituisce solo un valore ... –

+0

@omegatai - Ho perso la clausola di raggruppamento, risposta aggiornata. – MuhammadHani

+0

no, ancora non funziona ... http://imgur.com/nQ2PA2u –

1

Per semplicità, ho chiamato il test query:

SELECT * 
FROM Test T JOIN (
SELECT t.placeId, Max(t.cnt) maxcnt 
FROM Test t 
GROUP BY t.placeId) T2 ON T.placeId = T2.placeId and T.cnt = T2.maxcnt 

Ecco il Fiddle.

BTW - Test =:

SELECT uvo.userVotedId, p.placeId, count(*) as cnt 
    FROM users as u 
    INNER JOIN users_votes as uvo 
    ON u.userId = uvo.userVotedId 
    INNER JOIN places as p 
    ON p.placeId = uvo.placeId 
    GROUP BY userVotedId, placeId 

Buona fortuna.

--edit - come richiesto, ecco il codice finale:

SELECT * 
FROM (SELECT uvo.userVotedId, p.placeId, count(*) AS cnt 
      FROM users as u, users_votes as uvo, places as p 
      WHERE u.userId = uvo.userVotedId AND p.placeId = uvo.placeId 
      GROUP BY userVotedId, placeId) T JOIN (
SELECT t.placeId, Max(t.cnt) maxcnt 
FROM (SELECT uvo.userVotedId, p.placeId, count(*) AS cnt 
      FROM users as u, users_votes as uvo, places as p 
      WHERE u.userId = uvo.userVotedId AND p.placeId = uvo.placeId 
      GROUP BY userVotedId, placeId) t 
GROUP BY t.placeId) T2 ON T.placeId = T2.placeId and T.cnt = T2.maxcnt 
+0

@omegatai - ho usato questo demo con il mio SQL e ha funzionato - ecco il violino:! http://sqlfiddle.com/#!2/23bd7/6 – sgeddes

+0

ho appena realizzato la soluzione doesn funziona abbastanza Vedi qui: http://sqlfiddle.com/#!2/6a8f4/1 –

Problemi correlati