2011-11-28 16 views
8

Ho due tabelle e cerco di trovare il "post" con il punteggio più alto al giorno.Gruppo MySQL per e max restituisce righe errate

CREATE TABLE IF NOT EXISTS `posts_points` (
    `post_id` int(10) unsigned NOT NULL, 
    `comments` smallint(5) unsigned NOT NULL, 
    `likes` smallint(5) unsigned NOT NULL, 
    `favorites` smallint(5) unsigned NOT NULL, 
    PRIMARY KEY (`post_id`) 
) ENGINE=MyISAM DEFAULT CHARSET=utf8; 


CREATE TABLE IF NOT EXISTS `posts` (
    `profile_id` int(10) unsigned NOT NULL, 
    `post_id` int(10) unsigned NOT NULL, 
    `pubdate_utc` datetime NOT NULL, 
    PRIMARY KEY (`post_id`), 
    KEY `profile_id` (`profile_id`), 
) ENGINE=MyISAM DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC; 

Ho provato la query qui sotto. Restituisce il punteggio corretto ma le altre colonne sono solo righe casuali. Che cosa sto facendo di sbagliato ?

SELECT p.post_id, p.profile_id 
    , MAX(t1.score) 
    , DATE_FORMAT(t1.pubdate_utc, '%d %b') post_date 
    , DATE(t1.pubdate_utc) mydate 
FROM 
(
    SELECT p.profile_id, p.post_id, p.pubdate_utc 
     , (pp.comments + pp.likes + pp.favorites) AS score 
    FROM posts p 
    INNER JOIN posts_points pp ON p.post_id = pp.post_id 
) t1 
INNER JOIN posts p ON t1.post_id = p.post_id 
    AND t1.pubdate_utc = p.pubdate_utc 
GROUP BY mydate 
ORDER BY mydate DESC 
LIMIT 18; 
+2

+1 per includere la definizione della tabella – ManseUK

+0

Non stai facendo nulla di male.Le funzioni aggregate non influiscono sul valore di altre colonne. Sembrano essere "casuali". –

+0

Il raggruppamento per data dovrebbe generare quel comportamento strano. – Alfabravo

risposta

0
Column1 Column2 
C  d 
A  any thing 
D  y 
B  z 

Gli ordini dati Colonna1 allora sembra che questo ..... orderby solo ordina la prima colonna ....

Column1 Column2 
A  any thing 
B  z    
C  d 
D  y 
0

è un po 'difficile da capire cosa vuoi fare.

Le parole (colonne (post, commenti, preferiti) e PK), ho capito che si aggiornano i valori in aumento e non si registra ogni votazione.

ciò selezionate restituisce i dati del messaggio, e il punteggio, ordinando punto più grande, limitate a 18.

 SELECT P.post_id, 
       P.profile_id, 
       (PP.comments + PP.likes + PP.favorites) AS score, 
       DATE_FORMAT (P.pubdate_utc, '%d %b') AS post_data, 
       DATE (P.pubdate_utc) AS mydate 
      FROM posts P 
    INNER JOIN posts_points PP 
      ON (= P.post_id PP.post_id) 
     ORDER BY 3 DESC 
     LIMIT 18; 

Se che si desidera selezionare il maggior numero di voti della giornata, è necessario registrare Mi piace/favs diversi, ha bisogno di dati in quella tabella (posts_points).

+0

'posts_points' è un summary_table che ho fatto per eseguire il debug e velocizzare le cose. Ogni commento, come e preferito è in realtà registrato separatamente. Sembra che la tua ricerca trovi i post con il punteggio più alto. Sto cercando di trovare il post con il punteggio più alto al giorno negli ultimi 18 giorni. Non so se lo faccia. – user1070125

+0

Ciao, come è la sua struttura? Dove il record commenti/favs/likes? Se necessario, è possibile modificare le tabelle? – Cristian

0

Wow! Difficile. Ad esempio, c'è sempre la possibilità di cravatte per max.

La soluzione seguente crea un elenco intermedio di max_scores del giorno, quindi ottiene tutti i post i cui punteggi sono uguali al massimo per il loro giorno. Restituisce i legami, quindi puoi ottenere due file per un dato giorno. Chiedo il tuo perdono che non posso testarlo, quindi di dare un feedback, e sono sicuro che possiamo ottenere questo per fare ciò che ti serve.

SELECT p.profile_id, p.post_id, p.pubdate_utc 
, DATE_FORMAT(p.pubdate_utc, '%d %b') AS post_date 
, DATE(p.pubdate_utc) AS mydate 
, (pp.comments + pp.likes + pp.favorites) AS score 
FROM posts p 
INNER JOIN posts_points pp ON p.post_id = pp.post_id 
INNER JOIN 
(
    SELECT p.pubdate_utc AS max_date, 
    (pp.comments + pp.likes + pp.favorites) AS max_score 
    FROM posts p2 
    INNER JOIN posts_points pp2 ON p2.post_id = pp2.post_id 
) m ON score = m.max_score 
AND mydate = m.max_date 
ORDER BY mydate DESC 
LIMIT 18; 
0

si può vedere questo query di .Inner è innanzitutto recuperare le righe che hanno lo stesso post_id sia in tabella di somma (+ pp.comments pp.likes + pp.favorites) come punteggio Outer query viene prendere max punteggio e facendo gruppo entro la data saggia ....

SELECT post_id, profile_id 
    , MAX(score) 
    , DATE_FORMAT(pubdate_utc, '%d %b') post_date 
    , DATE(pubdate_utc) as mydate 
FROM 
(
    SELECT p.profile_id, p.post_id, p.pubdate_utc 
     , (pp.comments + pp.likes + pp.favorites) AS score 
    FROM posts p 
    INNER JOIN posts_points pp ON p.post_id = pp.post_id 
) 
GROUP BY pubdate_utc 
ORDER BY pubdate_utc DESC 
2

Mi imbatto in questo problema tutto il tempo. Quando MySQL esegue una funzione di aggregazione, per qualsiasi colonna non aggregata, trascina semplicemente i primi dati che attraversa per quel gruppo, indipendentemente dal fatto che sia dalla riga MAX o meno. Quindi ciò che devi fare è ordinare i dati in una query interna in modo tale che i valori massimi siano primi nei loro gruppi. Verifica se questo funziona per te:

SELECT t.post_id, 
     t.profile_id, 
     t.score, 
     t.pubdate_utc 
FROM (SELECT p.profile_id, 
      p.post_id, 
      p.pubdate_utc, 
      (pp.comments + pp.likes + pp.favorites) score 
     FROM posts p 
     JOIN posts_points pp ON p.post_id = pp.post_id 
     WHERE p.pubdate_utc >= DATE_ADD(DATE(NOW()), INTERVAL -17 DAY) 
     ORDER BY score DESC 
    ) t 
GROUP BY DATE(t.pubdate_utc) DESC 
; 

Si noti che non uso qui la funzione MAX. Ordinando per punteggio decrescente e poi raggruppando per data nella query esterna verrà visualizzato il punteggio più alto per data. Notare anche che inserisco la clausola WHERE nella query interna. Le query interne come questa (a volte necessarie) non sono molto efficienti, poiché non hanno indici per la query esterna da ottimizzare, quindi assicurati che il set di risultati interno sia il più piccolo possibile. Infine, nota GROUP BY DATE (t.pubdate_utc). Se non lo riducessi alle sole informazioni sulla data, ci sarebbero molti più di 18 risultati, come poi contano anche i tempi.

Edit: Cambiato INTERVAL -17 DAY per dare fino a 18 risultati, invece di 19.

Problemi correlati