• User Attivo

    Mysql - record trovato piu volte

    Ciao,
    mi trovo di fronte ad una richiesta mysql che fin ora non mi era mai capitata...

    Ho una tabella per delle visualizzazioni dove salvo id e data ogni volta che viene visualizzata una pagina. Lo stesso id può essere visualizzato più volte, viene quindi inserita una nuova riga ogni volta che viene visualizzato.

    es tabella.
    id data
    1 1343256423
    2 1343256423
    1 1343256423
    3 1343256423
    ecc ecc

    Vorrei sapere quale id viene trovato più volte all'interno della tabella per sapere quale pagina è stata più visualizzata.

    Esiste una funzione MySql tipo DISTINCT o GROUP BY che però mi restituisca solo l'id trovato più volte?

    Oppure esiste qualcosa in php? Tipo mysql_num_rows ma che restituisca solo l'id trovato più volte?

    Sicuramente il tutto si può fare con piu verifiche in php, però mi sembra strano non esista qualcosa di simile, ma ora non mi viene in mente...

    Ciao
    Grazie


  • ModSenior

    Ciao alebal,
    dovresti fare cosi:
    SELECT * FROM tabella GROUP BY id HAVING count(id) > 1


  • User Attivo

    Ciao, grazie per la rispopsta immediata, ma non sembra funzionare...:crying:

    Mi sono andato a rivedere la clausola having che proprio non mi ricordavo e non credo di aver mai usato fin'ora.

    Cosi come me l'hai postata la clausola verifica che i record trovarti con group by siano almeno più di uno, ma purtroppo nel mio caso è molto probabile siano sempre più di uno

    es
    id data
    1 1343256423
    1 1343256423
    1 1343256423
    2 1343256423
    2 1343256423
    2 1343256423
    2 1343256423

    in questo caso la query restituisce sempre l'id 1 (perche trovato comunque piu di una volta) ma in realta l'id 2 ha piu righe nella tabella.

    Però credo siamo vicini a quello che sto cercando, la query raggruppa per id e conosce il numero di righe trovate per ogni group, ora basterebbe fargli capire che deve trovare il numero maggiore di righe trovate all'interno di un gruppo

    Forse qualcosa tipo
    SELECT * FROM tabella GROUP BY id HAVING count(id) > MAX qualcosa...

    oppure
    SELECT * FROM tabella GROUP BY id HAVING MAX(count(id))

    ma con having non saprei proprio come scriverla...

    Mi date un ultimo aiutino

    Grazie
    Ciao


  • ModSenior

    Ah scusa avevo capito male ciò che chiedevi, prova cosi:
    SELECT * FROM tabella GROUP BY id HAVING count(id) = (SELECT count(id) AS n_trovati FROM tabella GROUP BY id ORDER BY n_trovati DESC LIMIT 1)


  • User Attivo

    Funziona:D... grazie...

    Tanto per capire se ho capito...

    la prima query come prima grazie ad having va a vedere quante righe ci sono in ogni gruppo

    La seconda salva in n_trovati gli id che count conta sempre suddividendoli in gruppi. Con order by n_trovati desc limit 1 li ordina in ordine decrescente e seleziona solo l'ultimo che inevitabilmente è il più grande

    Mettendole assieme le due e usando la seconda come parametro delle query having, seleziono l'id trovato in più righe, che è quello che a me interessa..

    Ho capito giusto cosa fa?

    Poi ho un dubbio su un ultima ottimizzazione, ci starebbe bene un order by id LIMIT 1 anche alla fine dopo la seconda query (comanderebbe praticamente la prima) tanto per non rischiar di far girare a vuota o più del necessario la prima query? O scasserebbe tutto??
    tipo:
    SELECT * FROM tabella GROUP BY id HAVING count(id) = (SELECT count(id) AS n_trovati FROM tabella GROUP BY id ORDER BY n_trovati DESC LIMIT 1) ORDER BY id LIMIT 1

    Un ultima cosa, non avevo mai concepito l'idea di utilizzar una query come parametro di una query.. mi hai aperto un mondo... forse in futuro mi risparmierò un sacco di tempo e di codice... grazie


  • ModSenior

    Si hai capito bene su come funziona.
    Se hai 2 id che sono presenti lo stesso numero di volte, ed inserisci il limit non otterrai ciò che volevi.
    Inserire quel limit per ottimizzare la query è, a mio avviso, inutile in quanto deve comunque controllare l'intera tabella per effettuare il raggruppamento, una cosa che potresti fare per aumentare la velocità di lettura della query è mettere il campo id come indice.
    Ho fatto un test in locale, con 5000 dati inseriti nella tabella senza indice la query impiega al massimo 0.0092 sec, mentre utilizzando l'indice impiega meno di metà del tempo. I tempi li ho presi con la cache disabilitata, per cui direi che non dovresti avere grandissimi problemi.

    Le subquery esistono da parecchio tempo in MySQL in alcuni casi possono tornare utili.


  • User Attivo

    Grazie mille... capito, come indice ho usato un id_riga in autoincrement, forse però a questo punto non serve a un tubo... magari lo levo e metto l'id ricercato?

    Per non rischiar di fare impiegare troppo tempo alla query nel cercar tra troppe righe ho anche pensato, di chiamarla "il più visto della settimana" cosi cancello man mano tutti i record che son li da più di 7 giorni, e salvo non mi facciano centinaia di migliaia di visualizzazioni al giorno (magari accadesse...) non dovrei correre il rischio di tempi troppo lunghi, anche se inserendo una riga per ogni visualizzazione sicuramente ci saranno molte record duplicati.


  • ModSenior

    No, non devi creare un nuovo campo come indice ma impostare quello che viene poi utilizzato nella query.


  • User Attivo

    Un ultimo dubbio...

    Ho provato a impostare l'id come primary key , ma non gli piace, credo proprio perche id può essere duplicato.

    Fatto cosi
    CREATE TABLE IF NOT EXISTS animali_video_vis_settimana (
    id_video int(11) NOT NULL,
    id_animale int(11) NOT NULL,
    video varchar(255) NOT NULL,
    data_ins varchar(255) NOT NULL,
    PRIMARY KEY id_video (id_video)
    ) ENGINE=MyISAM DEFAULT CHARSET=latin1;

    Dice cosi
    Errore

    Query SQL:

    --
    -- Dump dei dati per la tabella animali_video_vis_settimana

    INSERT INTO animali_video_vis_settimana ( id_video , id_animale , video , data_ins )
    VALUES ( 1, 13, 'EVXz3i9GVqc', '1343256423' ) , ( 1, 13, 'EVXz3i9GVqc', '1343256431' ) , ( 1, 13, 'EVXz3i9GVqc', '1343256440' ) , ( 4, 13, 'PPqpNv6m1To', '1343317797' ) , ( 4, 13, 'PPqpNv6m1To', '1343317804' ) , ( 4, 13, 'PPqpNv6m1To', '1343317808' ) , ( 4, 13, 'PPqpNv6m1To', '1343317844' ) , ( 6, 13, 'dXHUVw_QHMw', '1343341072' ) , ( 6, 13, 'dXHUVw_QHMw', '1343341077' ) , ( 6, 13, 'dXHUVw_QHMw', '1343341090' ) , ( 6, 13, 'dXHUVw_QHMw', '1343341093' ) , ( 6, 13, 'dXHUVw_QHMw', '1343341108' ) , ( 6, 13, 'dXHUVw_QHMw', '1343341114' ) ;

    Messaggio di MySQL: Documentazione
    #1062 - Duplicate entry '1' for key 1

    Basta key senza primary???


  • ModSenior

    Si devi mettere come semplice key, visto che sono valori ripetuti.


  • User Newbie

    Ciao, cercando sul forum ho trovato questo messaggio che "penso" possa aiutarmi.
    Mi trovo in una situazione dove a fronte di una ricerca devo restituire un risultato composto da una struttura e più partenze.
    Nel dettaglio:
    ho 2 tabelle una prodotti e una servizi. Dal form di ricerca cerco tutti gli hotel che sono in una destinazione che hanno delle partenze dal ....
    la query di risposta che ho scritto è così composta:

    SELECT * FROM catalog_service AS s INNER JOIN catalog AS p ON s.lid=p.lid WHERE s.departure >='datapartenza' AND p.template=4 ORDER BY s.sid DESC LIMIT 0,10;

    La query funziona ma così nel successivo ciclo while ,mi restituisce lo stesso hotel ripetutto per il numero di partenze, io invece vorrei avere solo 1 hotel con tutte le sue partenze.
    Pensavo che la soluzione fosse nel GROUP by e ho preso spunto dalla vostra risposta....ma non ci ho capito niente.

    Ciao e Grazie


  • User Attivo

    Ciao,
    riapro questo post perchè ho una piccolissima variante da fare sulla soluzione dell'altra volta.

    Vorrei non più solo il più visto, ma "i più visti", esempio i 5 più visti di questa settimana

    Ho subito pensato bastasse cambiare il limit a questa query e fare un while..
    SELECT * FROM tabella GROUP BY id HAVING count(id) = (SELECT count(id) AS n_trovati FROM tabella GROUP BY id ORDER BY n_trovati DESC LIMIT 1)

    Ma a mysql non piace... dice...
    #1242 - Subquery returns more than 1 row

    Come ne esco??
    Si può fare con questo tipo di query?

    Ciao
    Grazie


  • ModSenior

    Togli il group by dalla subquery e funziona, anche perchè non credo proprio che ti serva visto che usa l'id.


  • User Attivo

    Non mostra piu nulla senza group
    $query_piu_visti = "SELECT * FROM ".$prefix."piu_visti_sett GROUP BY id_news HAVING count(id_news) = (SELECT count(id_news) AS n_trovati FROM ".$prefix."piu_visti_sett ORDER BY n_trovati DESC LIMIT 5)";
    //echo $query_piu_visti;
    $piu_visti_query = mysql_query($query_piu_visti, $db);
    while($row_piu_visti = mysql_fetch_array($piu_visti_query)){


  • ModSenior

    Ma a cosa ti serve la subquery in questo caso? Perchè non ordini usando il count e applichi un limit?


  • User Attivo

    Fondamentalmente perche ora non so come toglierla...

    Cioè dopo having uguale cosa metto?

    SELECT * FROM ".$prefix."piu_visti_sett GROUP BY id_news HAVING count(id_news) =..........


  • ModSenior

    Puoi postare la struttura di piu_visti_sett?


  • User Attivo

    Fatta cosi semplice semplice
    CREATE TABLE IF NOT EXISTS streaming_up_tv_piu_visti_sett (
    id_news int(11) NOT NULL,
    titolo varchar(255) NOT NULL,
    img varchar(255) NOT NULL,
    data_ins varchar(255) NOT NULL,
    KEY id_news (id_news)
    ) ENGINE=MyISAM DEFAULT CHARSET=latin1;

    Poi sulla pagina di output del singolo post inserisco e cancello i più vecchi di una settimana


  • User Attivo

    E' davvero cosi un casino???

    Di solito rispondi molto veloce...


  • User Attivo

    Ho provato cosi
    SELECT count(id_news) AS n_trovati, id_news, titolo, img FROM ".$prefix."piu_visti_sett GROUP BY id_news ORDER BY n_trovati DESC LIMIT 5

    Cioè togliendo la parte a sinistra di having ed effettivamente ne mostra 5 e non sembra lamentarsi più di tanto...

    Ho però qualche dubbio sull'ordinamento, cioè sul fatto che siano effettivamente i 5 più visitati... Secondo voi??? Saranno giusti con la query scritta cosi?