Query SQL per ricavare percentuale di messaggi letti

di il
17 risposte

Query SQL per ricavare percentuale di messaggi letti

Buongiorno a tutti.

Ho un problema con una query in MySQL che utilizzo con PDO.

Non è esattamente un problema, ma piuttosto la ricerca di una soluzione per un'aggiunta.

Forse è meglio mostrare la situazione. Le tabelle in gioco sono le seguenti:

CHAT2

CHAT_MEMBERS

USERS

Per il prelievo dei dati, al momento utilizzo la seguente query (semplificata):

SELECT

    chat2.chatId,

    chat2.chatDate,

    chat2.chatText,

    (cm.chat_read) AS chatRead,

    chat2.parentChat_id AS chatRif,

    cm.sender,

    cm.chat_id as chatId_cm,

    users.userName,

    users.ranking,

    (SELECT GROUP_CONCAT(users.userName)

                    FROM chat_members

                    INNER JOIN users ON chat_members.user_Id = users.userId

                    WHERE chat_members.chat_id = chat2.chatId

                              AND sender = 0) AS addressess

FROM chat2

INNER JOIN users ON chat2.user_Id = users.userId

INNER JOIN chat_members AS cm ON chat2.chatId = cm.chat_id

WHERE cm.user_Id = :userId


ORDER BY chatRif DESC, chat2.chatDate DESC

Quello che desidererei è trovare un modo per calcolare la percentuale dei messaggi non letti. Ora, trasferisco solo (cm.chat_read) AS chatRead, ma non è molto significativo.

Insomma, vorrei modificare la questi per ottenere una cosa del genere:

(SELECT chat2.user_id, chat2.chatId, COUNT(cm.chat_read) AS totaleLetti
        FROM chat2
		INNER JOIN chat_members AS cm ON chat2.chatId = cm.chat_id
        WHERE cm.chat_id = 26 AND cm.chat_read = 1
        GROUP BY chat2.user_id) AS letti

(SELECT chat2.user_id, chat2.chatId, COUNT(cm.chat_read) AS totale
        FROM chat2
		INNER JOIN chat_members AS cm ON chat2.chatId = cm.chat_id
        WHERE cm.chat_id = 26
        GROUP BY chat2.user_id) as totali
        
letti / totali * 100

Spero sia chiaro. Se qualcuno potesse  aiutarmi, gliene sarei grato.

17 Risposte

  • Re: Query SQL per ricavare percentuale di messaggi letti

    Messaggiletti/totalemessaggi*100

  • Re: Query SQL per ricavare percentuale di messaggi letti

    Grazie per la risposta.

    Sì, appunto, l'ho scritto anch'io. Ma, dove inserisco (e come) l'operazione nella mia query in SQL?

  • Re: Query SQL per ricavare percentuale di messaggi letti

    16/10/2023 - BennyBatt ha scritto:


    Ma, dove inserisco (e come) l'operazione nella mia query in SQL?

    Volendo potresti anche fare il calcolo direttamente in PHP, una volta ottenuti i conteggi che ti interessano: non è obbligatorio fare tutto in SQL.

  • Re: Query SQL per ricavare percentuale di messaggi letti

    select
          (select COUNT(cm.chat_read) 
           FROM chat2
           where cm.chat_read=:Condizione) AS totaleLetti,
          (select COUNT(cm.chat_read)) as totalemail
    from chat2     

    se non erro avrai un record e due campi:

    totaleletti      totalemail

    il resto fai tu…

  • Re: Query SQL per ricavare percentuale di messaggi letti

    Eh, purtroppo sto ancora studiando, e non so ancora bene come comportarmi.

    Ho modificato la query introducendo una delle tue subquery, in questo modo:

    SELECT
    	chat2.chatId,
    	chat2.chatDate,
    	chat2.chatText,
    	(cm.chat_read) AS chatRead,
    	chat2.parentChat_id AS chatRif,
        (select COUNT(cm.chat_read)) as totale,
    	cm.sender,
    	cm.chat_id as chatId_cm,
    	users.userName,
    	users.ranking,
        (SELECT GROUP_CONCAT(users.userName)
        	FROM chat_members
        	INNER JOIN users ON chat_members.user_Id = users.userId
        	WHERE chat_members.chat_id = chat2.chatId
        		AND sender = 0) AS addressess
    FROM chat2
    INNER JOIN users ON chat2.user_Id = users.userId
    INNER JOIN chat_members AS cm ON chat2.chatId = cm.chat_id
    WHERE cm.user_Id = 2
    	AND cm.chat_deleted = 0
    	AND cm.chat_id NOT IN (
            SELECT chatId FROM chat_archive
            WHERE userId = 2
            )
    ORDER BY chatRif DESC, chat2.chatDate DESC;

    invece di valorizzarmi la colonna totale per ognuna delle tuple corrispondenti (la query base, per l'utente 2, restituisce 5 righe), mi restituisce una sola riga.

    Cosa sbaglio?

  • Re: Query SQL per ricavare percentuale di messaggi letti

    Perché tutte quelle join?

    Devi avere l'elenco deli messaggi

    L'elenco avrà un campo letta (si/no)

    Devi usare solo un campo

    La prima volta conti le mail o chat risposte

    Con la seconda conti tutte le mail o chat

    Se osservi la query ho usato solo un campo.

    Crea la tabella di partenza

    Tipo select * from tabella where utente='pippo' se vuoi la % delle mail risposte di pippo

    Ogni query restituisce una tabella di dati.

    Trovata la tua tabella di risposta, applichi (sostituendo all'esempio di prima) le condizioni “tutte” e “lette”.

    Alla fine avrai per pippo due campi e un record

    Tutte e lette

    Inizia creando le query che generano come.risposta la tua tabella di partenza.

    Tipo:

    Select * from tabellachat where utentechat=pippo 

    La tabella di risposta, chiamiamola (A) fra gli altri avrà letto/nonletto

    A questo punto devi ottenere:

    select

          (select COUNT(letto) 

           FROM (A)

           where letto=:Condizione) AS totaleLetti,

          (select COUNT(letto)) as totalemail

    from chat2(A)

    Dove (A) è la tua tabella ottenuta con tutte le join che vuoi.

    Suddividi sempre il problema e ripassa le select di select

    Io ho dato per scontato che parliamo di mysql.

    :Condizione è scritto come variabile (parametro da passare) ma tu puoi scrivere direttamente il valore da filtrare.

    Spero di essere stato chiaro nella spiegazione.

  • Re: Query SQL per ricavare percentuale di messaggi letti

    Grazie per la risposta.

    Spero di non abusare della tua pazienza. 

    Allora, la query iniziale funziona, e mi permette di ottenere i vari messaggi e le varie informazioni dalla tabella chat2, che è in relazione alla tabella chat_members (per ogni tupla in chat2 ci possono essere n tuple in questa tabella a seconda di quanti sono i destinatari), e ovviamente è collegata alla tabella users per i dati restati che mi occorrono. La query in questione redige una lista dei messaggi sia che siano stati inviati dall'utente (il cui id è la voce condizionale della query, e prevede una variabile gestita con PDO) o che siano stati da lui ricevuti.

    L'idea è quella di calcolare la percentuale di lettura per ogni tupla di chat2 direttamente nella query in oggetto, inserendo delle subqueries. Ho fatto dei tentativi, ieri. Questa query, a se stante, ovviamente restituisce il risultato voluto:

    SELECT COUNT(cm.chat_read)
    
    FROM chat_members AS cm
    
    INNER JOIN chat2 ON chat2.chatId = cm.chat_id
    
    WHERE cm.chat_read = 1 AND chat2.chatId = 25

    Ma, non riesco ad inserirla come subquery generale per tutte le tuple nella mia query base per tutti gli id di chat2 elaborati. Forse non è possibile o, più probabilmente, è possibile ma io non capisco come fare. 

    Quello che tu proponi, se non ho capito male è una nuova query esterna alla mia.  Certo è una strada percorribile. A meno che tu non intenda la struttura come base per la subquery in discussione?

    Scusa se ti sembrerà irritante la risposta, ma sono ancora ai rudimenti di SQL…

  • Re: Query SQL per ricavare percentuale di messaggi letti

    Ogni query restituisce una tabella che sia piena o vuota.

    Fai una query della query.

    Ti ho suggerito di studiare le select di select cioè dati estrapolati da altre subquery.

    17/10/2023 - BennyBatt ha scritto:


    (SELECT COUNT(cm.chat_read) FROM chat_members AS cm INNER JOIN chat2 ON chat2.chatId = cm.chat_id WHERE cm.chat_read = 1 AND chat2.chatId = 25)

    Fai finta che questa sia la tabella myquery. Fai una query su questa. (Ammesso che questa select che hai scritto tu dia le informazioni che ti servono)

    Usa le parentesi.

  • Re: Query SQL per ricavare percentuale di messaggi letti

    Quindi, se non capito male, la strada è quella di utilizzare una di queste possibilità:

    https://www.mysqltutorial.org/mysql-derived-table/

    https://www.techwell.com/techwell-insights/2022/12/common-table-expressions-mysql-8

    Giusto?

    In effetti, è abbastanza logico.  Se è così, ci studierò sopra. L'alternativa è, come giustamente suggerito da Alka è elaborare il tutto in PHP. Mi piacerebbe riuscirci con SQL, però, per approfondire le mie conoscenze.

  • Re: Query SQL per ricavare percentuale di messaggi letti

    17/10/2023 - BennyBatt ha scritto:


    L'alternativa è, come giustamente suggerito da Alka è elaborare il tutto in PHP. Mi piacerebbe riuscirci con SQL, però, per approfondire le mie conoscenze.

    Preciso che la mia proposta non era elaborare tutto in PHP, ma solo il necessario.

    Per esemplificare, invece di creare una query complessa con la quale cerchi di farti restituire direttamente il valore finale, ossia una percentuale calcolata sui conteggi di record provenienti da query diverse, nulla ti vieta di eseguire le due query separatamente in PHP, la prima per ottenere il totale che ti serve e la seconda per ottenere il valore da confrontare, poi una volta acquisiti questi valori, il calcolo mero della percentuale di quel valore sul totale puoi determinarlo direttamente in PHP con una banale espressione.

  • Re: Query SQL per ricavare percentuale di messaggi letti

    Allora, ho provato ma mi da dei risultati farlocchi.

    Mi spiego: se applico la query base (quella suddetta), sostituendo al parametro PDO :user_id un valore qualsiasi (2, in questo caso), i risultati vengono esposti in modo corretto. Per dettagliare:

    SELECT
      chat2.chatId,
      chat2.chatDate,
      chat2.chatText,
      (cm.chat_read) AS chatRead,
      chat2.parentChat_id AS chatRif,
      cm.sender,
      cm.chat_id as chatId_cm,
      users.userName,
      users.ranking,
      (SELECT GROUP_CONCAT(users.userName)
       FROM chat_members
       INNER JOIN users ON chat_members.user_Id = users.userId
       WHERE chat_members.chat_id = chat2.chatId
             AND sender = 0) AS addressess
    FROM chat2
    INNER JOIN users ON chat2.user_Id = users.userId
    INNER JOIN chat_members AS cm ON chat2.chatId = cm.chat_id
    WHERE cm.user_Id = 2
          AND cm.chat_deleted = 0
          AND cm.chat_id NOT IN (
            SELECT chatId FROM chat_archive
            WHERE userId = 2
          )
    ORDER BY chatRif DESC, chat2.chatDate DESC

    mi restituisce:

    ma il mio tentativo con una derived table, questa:

    SELECT chatId, COUNT(chatRead) AS totale
    FROM
    (SELECT
      chat2.chatId,
      chat2.chatDate,
      chat2.chatText,
     (cm.chat_read) AS chatRead,
      chat2.parentChat_id AS chatRif,
      cm.sender,
      cm.chat_id as chatId_cm,
      users.userName,
      users.ranking,
      (SELECT GROUP_CONCAT(users.userName)
       FROM chat_members
       INNER JOIN users ON chat_members.user_Id = users.userId
       WHERE chat_members.chat_id = chat2.chatId
             AND sender = 0) AS addressess
    FROM chat2
    INNER JOIN users ON chat2.user_Id = users.userId
    INNER JOIN chat_members AS cm ON chat2.chatId = cm.chat_id
    WHERE cm.user_Id = 2
          AND cm.chat_deleted = 0
          AND cm.chat_id NOT IN (
            SELECT chatId FROM chat_archive
            WHERE userId = 2
          )
    ORDER BY chatRif DESC, chat2.chatDate DESC) AS Q1

    Restituisce:

    E il risultato è 2 volte sbagliato, perché non esegue come dovrebbe l'iterazione tra le righe di Q1, e somma 5 (che è il numero delle righe di Q1).

    Iniziare la query con il riferimento a cm (che è contenuto in Q1), in questo modo:

    SELECT chatId, COUNT(cm.chat_read) AS totale

    genera l'errore “unknown column 'cm.chat_read' in 'field list'”.

    Certamente sbaglio a impostare le istruzioni. Portate pazienza…

  • Re: Query SQL per ricavare percentuale di messaggi letti

    Io ho messo un parametro a caso solo per rendere un esempio nel caso in cui vuoi selezionare per utente o data o intervallo di date o quello che vuoi.

    Alla fine devi avere una tabella con

    Utente data letta ecc.. ecc… (anche se non ti serviranno gli altri campi)

    Su questa devi applicare la select finale (quella per la percentuale.

    Alla fine stai sommando

    Select count(lette) from… where lette=false

    Ed

    Select count(lette) from…

    La prima ti conta quante chat sono state aperte

    La seconda il totale delle chat.

    Forse devi esercitarti di più con sql. Pazienza! Vai di php.

    P.s. non serve “order by" “group” ecc… tanto avrai solo un record alla fine, ti porta solo pasticci. A parte che group ti falsa il totale dei record…

  • Re: Query SQL per ricavare percentuale di messaggi letti

    Ho trovato una soluzione, utilizzando sia PHP, sia una query SQL aggiuntiva.

    Anzitutto, ho applicato la prima query che ho presentato, che mi restituisce la lista delle tuple summenzionata.

    Poi, tramite una PDO::FETCH_ASSOC, ottengo la matrice relativa.

    Ciclando tra le tuple, applico una query che recupera i dati dalla tabella chat_members, quindi posso calcolare la percentuale. In dettaglio:

    foreach ($dataChat as $row){
    	$chats = new Chat();
          $chatRead = $chats->listRead($row['chatId']);
       	  $perc = $chatRead['letti']/$chatRead['tot'] *100;

    Tralascio la parte rimanente (lunghissima) della routine, ovviamente.

    Questa la query relativa (applicata ad una routine con PDO):

    SELECT DISTINCT (SELECT COUNT(chat_read)
    FROM chat_members
    WHERE sender <> 1 AND chat_id = :chId1) AS tot,
        (SELECT COUNT(chat_read)
         FROM chat_members
         WHERE sender <> 1 AND chat_read = 1 AND chat_id = :chId2) as letti
         FROM chat_members)

    Ovviamente, non è l'opzione mia di studio, dove avrei voluto far tutto tramite una singola query, ma la soluzione è più semplice, e anche più manutenibile.

    Se avete qualche commento, suggerimento o altro, sono ben accetti.

    Grazie.

  • Re: Query SQL per ricavare percentuale di messaggi letti

    Ma non bastava la quarta risposta?

    select
          ((select COUNT(cm.chat_read) 
           FROM chat2
           where cm.chat_read=:Condizione) /
          (select COUNT(cm.chat_read)) * 100) as percentuale
    from chat2 
    group by percentuale;
Devi accedere o registrarti per scrivere nel forum
17 risposte