• User Attivo •

    [MySQL] Ordinamento a seguito di sottrazione? (from...order by...)

    Ciao,
    ho una singola query che prende i valori da 3 tabelle. In una di queste tabelle ci sono 2 campi che riportano i voti positivi e quelli negativi. Dovrei estrarne una classifica dei più votati e ovviamente la classifica deve essere fatta sottraendo i voti negativi dal totale di quelli positivi.

    Al momento la classifica viene stampata tramite "ORDER BY votipositivi DESC LIMIT 3" ma è ovvio che l'utente con 20 voti positivi e 1 negativo è migliore di quello con 25 positivi e 10 negativi, per cui l'ordinamento attuale non va bene.

    Non ho idea però, sempre se sia possibile, di come strutturare una query che mi ordini i risultati DOPO aver fatto le dovute sottrazioni, anche con eventuali valori negativi.

    Mi sapete aiutare? 🙂


  • User Attivo •

    so che si possono sottrarre delle colonne ma valori di righe diverse non saprei.
    Non ti converrebbe estrarre tutti gli elementi con lo stesso ID, fare l'operazione da php e successivamente visualizzare i risultati ordinati?


  • User Attivo •

    @PietroR said:

    so che si possono sottrarre delle colonne ma valori di righe diverse non saprei.
    Non ti converrebbe estrarre tutti gli elementi con lo stesso ID, fare l'operazione da php e successivamente visualizzare i risultati ordinati?

    Eh... potrei... ma come?
    Ora il codice è questo

    [PHP][...] ORDER BY votipositivi DESC LIMIT 3";

    $query_result = mysqli_query($cnt, $query_select);
    
    while( $estrai = mysqli_fetch_assoc($query_result))
    { 
    

    echo $estrai['nome'] . ' <br />';
    echo $estrai['cognome'] . ' <br />';
    echo $estrai['votipositivi'] . ' <br />';
    echo $estrai['votinegativi'] . ' <br />';
    }
    [/PHP]
    e ovviamente me li stampa in sequenza esattamente come riportati dalla query. Al momento non ho idea di come potrei riorganizzarli in PHP... :gtsad:


  • ModSenior •

    Ciao,
    cosi dovrebbe andare bene:

    SEELCT *, (votipositivi/(votipositivi+votinegativi)) AS percentuale_votipositivi FROM tabella ORDER BY percentuale_votipositivi DESC LIMIT 3


  • User Attivo •

    @Thedarkita said:

    Ciao,
    cosi dovrebbe andare bene:

    SEELCT *, (votipositivi/(votipositivi+votinegativi)) AS percentuale_votipositivi FROM tabella ORDER BY percentuale_votipositivi DESC LIMIT 3

    Con questo metodo mi dà 2 tipi di errore:
    [PHP]query = "SELECT nome, cognome, messaggio, destinatario, (votipositivi/(votipositivi+votinegativi)) AS percentuale_votipositivi FROM mittenti, testo, destinatari WHERE id_mittente.mittenti = id_mittente.testo AND id_destinatario.destinatari = id_messaggio.testo ORDER BY percentuale_votipositivi DESC limit 3";
    [...]

    $query_result = mysqli_query($cnt, $query_select);
    
    while( $estrai = mysqli_fetch_assoc($query_result))
    { 
    

    echo $estrai['nome'] . ' <br />';
    echo $estrai['cognome'] . ' <br />';
    echo $estrai['votipositivi'] . ' <br />'; NOTICE: undefined index votipositivi
    echo $estrai['percentuale _votipositivi'] . ' <br />'; // risultato 0.8000 anzichè il numero di voti
    } [/PHP]

    inoltre
    persona A voti reali +8 -2
    persona B voti reali +3 -0
    persona C voti reali +1 -0
    perdona D voti reali +4 -1

    e dovrebbe restituirmeli in ordine A, B (o D), C mentre l'ordine restituito, con la formula di percentuale, è B - C - A :bho:


  • ModSenior •

    Allora una soluzione del tipo votipositivi-votinegativi dovrebbe essere migliore:

    
    SELECT nome, cognome, messaggio, destinatario, (votipositivi-votinegativi) AS percentuale_votipositivi FROM mittenti, testo, destinatari WHERE id_mittente.mittenti = id_mittente.testo AND id_destinatario.destinatari = id_messaggio.testo ORDER BY percentuale_votipositivi DESC limit 3
    
    

  • User Attivo •

    @Thedarkita said:

    Allora una soluzione del tipo votipositivi-votinegativi dovrebbe essere migliore:

    >
    SELECT nome, cognome, messaggio, destinatario, (votipositivi-votinegativi) AS percentuale_votipositivi FROM mittenti, testo, destinatari WHERE id_mittente.mittenti = id_mittente.testo AND id_destinatario.destinatari = id_messaggio.testo ORDER BY percentuale_votipositivi DESC limit 3
    
    >```
    La soluzione è buona per l'ordinamento, ma non per la stampa dei voti reali :gtsad:
    Ill codice che segue la query deve mostrare anche i voti totali sia positivi che negativi 
    

    while( $estrai = mysqli_fetch_assoc($query_result))
    {
    echo $estrai['nome'] . ' ' . $estrai['cognome'] . ' voti + ' . $estrai['votipositivi'] . ' -' . $estrai['votinegativi'];
    }

    Del tipo:
    pinco pallo voti +8 -2
    Wonder Woman voti  +4 -1
    Pippo Pluto voti +3 -0
    Super Pippo voti  +1 -0
    
    mente con la tua query me li ordina giusti ma mi stampa 
    
    pinco pallo: +6 -2
    Wonder Woman:  +3 -1
    Pippo Pluto: +3 -0
    Super Pippo:  +1 -0
    
    in pratica mi stampa il risultato della sottrazione anzichè il voto reale. I voti negativi sono ok perchè sono presi direttamente dalla tabella senza manipolazioni... ma il passo successivo sarà quello della lista "dei peggiori" dove ci troveremo davanti allo stesso problema ma a parti invertite...

  • ModSenior •

    Con la query che ho scritto io è impossibile, forse cambi tu il nome dopo AS e sovrascrivi il valore.


  • User Attivo •

    @Thedarkita said:

    Con la query che ho scritto io è impossibile, forse cambi tu il nome dopo AS e sovrascrivi il valore.

    Avevamo mezza ragione entrambi.
    Query reale:

    [PHP]$query = "SELECT nome, cognome, messaggio, destinatario, votipositivi, votinegativi FROM mittenti, testo, destinatari WHERE id_mittente.mittenti = id_mittente.testo AND id_destinatario.destinatari = id_messaggio.testo ORDER BY votipositivi DESC limit 3';[/PHP]

    la tua query invece

    [PHP]$query = 'SELECT nome, cognome, messaggio, destinatario, (votipositivi - votinegativi) AS percentuale_votipositivi FROM mittenti, testo, destinatari WHERE id_mittente.mittenti = id_mittente.testo AND id_destinatario.destinatari = id_messaggio.testo ORDER BY percentuale_votipositivi DESC limit 3';

    while( $estrai = mysqli_fetch_assoc($query)){
    echo $estrai['votipositivi']; // ERRORE: l'indice 'votipositivi' non esiste più perchè sostituito da percentuale_votipositivi.
    echo $estrai['percentuale_votipositivi']; // OK, ma numero sbagliato dato dal risultato della sottrazione[/PHP]

    La soluzione è stata ripetere i due campi

    [PHP]$query = 'SELECT nome, cognome, messaggio, destinatario, (votipositivi - votinegativi) AS percentuale_votipositivi, votipositivi, votinegativi FROM mittenti, testo, destinatari WHERE id_mittente.mittenti = id_mittente.testo AND id_destinatario.destinatari = id_messaggio.testo ORDER BY percentuale_votipositivi DESC limit 3';[/PHP]

    che sembra dia il giusto ordinamento e i giusti voti! :campione:


  • User Attivo •

    Purtroppo devo ricredermi... non va.

    La query è sempra la solita
    [PHP]$query = 'SELECT nome, cognome, messaggio, destinatario, (votipositivi - votinegativi) AS percentuale_votipositivi, votipositivi, votinegativi FROM mittenti, testo, destinatari WHERE id_mittente.mittenti = id_mittente.testo AND id_destinatario.destinatari = id_messaggio.testo ORDER BY percentuale_votipositivi DESC limit 3';

    $query_result = mysqli_query($cnt, $query);
    [/PHP]
    Come si vede è una semplice estrazione di valori. Entrambi i campi riportano valori positivi ma la sottrazione può non esserlo.
    Infatti il problema nasce quando i valori negativi sono superiori ai positivi. L'espressione deve fare un calcolo con risultato negativo (es: 5-7 = -2 ) e mi dà questo errore su MySQL 5.5:

    Warning: mysqli_query(): (22003/1690): BIGINT UNSIGNED value is out of range in '(mio_db.testo.votipositivi - mio_db.testo.votinegativi)' in F:\xampp1.8.3\htdocs\www\inc\migliori.inc.php on line 4

    La riga 4 è quella che materialmente fa la query $query_result = mysqli_query($cnt, $query)

    Il secondo problema è con MySQL 5.1: il problema precedente non me lo dà, ma in compenso mi restituisce questo strano ordinamento dei migliori voti (secondo lui)

    A voti +0 -1
    B voti +0 -3
    C voti +8 -2

    non riesco proprio a capirne la logica nè nel primo caso ma soprattutto nel secondo... mi sto demoralizzando... 😞

    EDIT:
    C'è anche un altro errore di cui non mi ero accorto
    Warning: mysqli_fetch_assoc() expects parameter 1 to be mysqli_result, boolean given in F:\xampp1.8.3\htdocs\www\inc\migliori.inc.php on line 7
    che equivale alla riga
    [PHP]
    while( $estrai = mysqli_fetch_assoc($query_result)){
    [/PHP]


  • User Attivo •

    Aggiorno questo post perchè credo di essere arrivato alla giusta soluzione!

    L'errore
    "Warning: mysqli_query(): (22003/1690): BIGINT UNSIGNED value is out of range in '(mio_db.testo.votipositivi - mio_db.testo.votinegativi)' in F:\xampp1.8.3\htdocs\www\inc\migliori.inc.php on line 4"

    l'ho risolto eliminando l'attibuto "unsigned" dal campo della tabella;

    Il corretto ordinamento dell'array l'ho ottenuto mediate una semplice modifica della query
    [PHP]
    $query = "SELECT nome, cognome, messaggio, destinatario, votipositivi, votinegativi FROM mittenti, testo, destinatari WHERE id_mittente.mittenti = id_mittente.testo AND id_destinatario.destinatari = id_messaggio.testo ORDER BY (votipositivi - votinegativi) DESC limit 3';
    [/PHP]

    Sembra che tutto funzioni correttamente sia su MySQL 5.1 che 5.5 :sun: