Time to first response by group members

Time to first group response for topics created within a given time period

Returns the time to first response by a member of a given group to “regular” (not Personal Message) topics created by a user who is not a member of the given group. The query’s :group_name parameter is set to “staff” by default. With that value, it will give the time to first response by staff members. You can change the value of that parameter to get response times for different groups. For example “customer_support”.

Note that dates should technically be supplied in the form yyyy-mm-dd, but the query would also accept dates in the form dd-mm-yyyy.

-- [params]
-- date :start_date
-- date :end_date
-- string :group_name = staff

WITH group_response_times AS (
    SELECT
        t.category_id,
        t.id AS topic_id,
        EXTRACT(EPOCH FROM (p.created_at - t.created_at)) / 60 AS response_time_minutes,
        p.user_id AS staff_user_id,
        ROW_NUMBER() OVER (PARTITION BY t.id ORDER BY p.created_at) AS row_num
    FROM posts p
    JOIN topics t ON t.id = p.topic_id
    WHERE t.user_id NOT IN (SELECT user_id
                                FROM group_users gu JOIN groups g ON g.id = gu.group_id
                                WHERE gu.user_id > 0 AND g.name = :group_name)
        AND p.user_id IN (SELECT user_id
                              FROM group_users gu JOIN groups g ON g.id = gu.group_id
                              WHERE gu.user_id > 0 AND g.name = :group_name)
        AND t.archetype = 'regular'
        AND t.deleted_at IS NULL
        AND p.post_type = 1
        AND p.deleted_at IS NULL
        AND t.created_at BETWEEN :start_date AND :end_date
)

SELECT
    category_id,
    topic_id,
    staff_user_id,
    ROUND(response_time_minutes::numeric, 2) AS response_time_minutes
FROM group_response_times
WHERE row_num = 1
ORDER BY category_id, response_time_minutes

Average time to first group response per category:

Uses the same logic as the previous query, but returns the average time to the first response by members of the given group per category for topics created by users who are not members of the given group within the time period set by the :start_date and :end_date parameters. As with the previous query, if the :group_name parameter is left at its default value of “staff”, it will return the average staff first response times for regular topics created by non-staff users.

-- [params]
-- date :start_date
-- date :end_date
-- string :group_name = staff

WITH group_response_times AS (
    SELECT
        t.category_id,
        t.id AS topic_id,
        EXTRACT(EPOCH FROM (p.created_at - t.created_at)) / 60 AS response_time_minutes,
        p.user_id AS staff_user_id,
        ROW_NUMBER() OVER (PARTITION BY t.id ORDER BY p.created_at) AS row_num
    FROM posts p
    JOIN topics t ON t.id = p.topic_id
    WHERE t.user_id NOT IN (SELECT user_id
                                FROM group_users gu JOIN groups g ON g.id = gu.group_id
                                WHERE gu.user_id > 0 AND g.name = :group_name)
        AND p.user_id IN (SELECT user_id
                              FROM group_users gu JOIN groups g ON g.id = gu.group_id
                              WHERE gu.user_id > 0 AND g.name = :group_name)
        AND t.archetype = 'regular'
        AND t.deleted_at IS NULL
        AND p.post_type = 1
        AND p.deleted_at IS NULL
        AND t.created_at BETWEEN :start_date AND :end_date
)

SELECT
    category_id,
    ROUND(AVG (response_time_minutes)::numeric, 2) AS average_response_time_minutes,
    COUNT(*) AS num_topics_with_staff_responses
FROM group_response_times
WHERE row_num = 1
GROUP BY category_id

Ciao @simon

Grazie per aver condiviso una potenziale soluzione per generare report mensili sul tempo di risposta del personale. Questo codice è ancora valido o esiste una versione aggiornata? Inoltre, è possibile creare questo report su base settimanale anziché mensile? Grazie mille.

1 Mi Piace

Non lo è. Onestamente, non sono sicuro di come abbia mai funzionato. Pubblicherò presto una versione aggiornata e ti avviserò quando sarà pronta.

Modifica: @IreneT
Ecco una versione corretta della query originale. Ignorerei quella query e guarderei le altre query che ho pubblicato in questa risposta. Fammi sapere se hai domande sulle query o se riscontri problemi nell’aggiungere i parametri richiesti alle query. Dai test di oggi, sto scoprendo che devo aggiornare la pagina dopo aver salvato una query di Data Explorer affinché i campi di immissione dei parametri vengano visualizzati sotto la query. (Potrebbe essere solo una stranezza del mio sito di sviluppo locale.)

-- [params]
-- int :months_ago = 1

WITH query_period AS (
SELECT
date_trunc('month', CURRENT_DATE) - INTERVAL ':months_ago months' as period_start,
date_trunc('month', CURRENT_DATE) - INTERVAL ':months_ago months' + INTERVAL '1 month' - INTERVAL '1 second' as period_end
),
staff_responses AS (
SELECT
DISTINCT ON (p.topic_id)
p.topic_id,
p.created_at,
t.category_id,
EXTRACT(MINUTE FROM (p.created_at - t.created_at)) AS response_time
FROM posts p
JOIN topics t
ON t.id = p.topic_id
AND t.category_id = ANY ('{46,25,43,40,44,35,22,7,20,17,6,12}'::int[])
JOIN users u
ON u.id = p.user_id
WHERE p.post_number > 1
AND u.admin = 't' OR u.moderator = 't'
ORDER BY p.topic_id, p.created_at
),
user_topics AS (
SELECT
t.id
FROM topics t
JOIN users u
ON u.id = t.user_id
WHERE u.admin = 'f' AND u.moderator = 'f'
)

SELECT
sr.category_id,
AVG(sr.response_time) AS "Tempo medio di prima risposta",
COUNT(1) AS "Argomenti a cui è stata data risposta"
FROM staff_responses sr
JOIN query_period qp
ON sr.created_at >= qp.period_start
AND sr.created_at <= qp.period_end
JOIN user_topics t
ON t.id = sr.topic_id
GROUP BY sr.category_id

Ciò che è stato modificato è:

--DATE_TRUNC('minute', p.created_at - t.created_at) AS response_time
EXTRACT(MINUTE FROM (p.created_at - t.created_at)) AS response_time

Sarei sorpreso se avessi scritto la vecchia query senza testarla. In ogni caso, la versione aggiornata funziona come previsto ora.

A memoria, questa query è stata scritta per un sito specifico e non era intesa per essere pubblicata su Meta. Ecco un paio di altre query utili per ottenere informazioni sui tempi di risposta dello staff:

Tempo alla prima risposta di gruppo per argomenti creati entro un dato periodo di tempo

Restituisce il tempo alla prima risposta di un membro di un dato gruppo a argomenti “regolari” (non messaggi personali) creati da un utente che non è membro del dato gruppo. Il parametro :group_name della query è impostato su “staff” per impostazione predefinita. Con questo valore, darà il tempo alla prima risposta dei membri dello staff. Puoi cambiare il valore di quel parametro per ottenere i tempi di risposta per gruppi diversi. Ad esempio “customer_support”.

Nota che le date dovrebbero tecnicamente essere fornite nel formato aaaa-mm-gg, ma la query accetterebbe anche date nel formato gg-mm-aaaa.

-- [params]
-- date :start_date
-- date :end_date
-- string :group_name = staff

WITH group_response_times AS (
    SELECT
        t.category_id,
        t.id AS topic_id,
        EXTRACT(MINUTE FROM (p.created_at - t.created_at)) AS response_time_minutes,
        p.user_id AS staff_user_id,
        ROW_NUMBER() OVER (PARTITION BY t.id ORDER BY p.created_at) AS row_num
    FROM posts p
    JOIN topics t ON t.id = p.topic_id
    WHERE t.user_id NOT IN (SELECT user_id
                                FROM group_users gu JOIN groups g ON g.id = gu.group_id
                                WHERE gu.user_id > 0 AND g.name = :group_name)
        AND p.user_id IN (SELECT user_id
                              FROM group_users gu JOIN groups g ON g.id = gu.group_id
                              WHERE gu.user_id > 0 AND g.name = :group_name)
        AND t.archetype = 'regular'
        AND t.deleted_at IS NULL
        AND p.post_type = 1
        AND p.deleted_at IS NULL
        AND t.created_at BETWEEN :start_date AND :end_date
)

SELECT
    category_id,
    topic_id,
    staff_user_id,
    response_time_minutes
FROM group_response_times
WHERE row_num = 1
ORDER BY category_id, response_time_minutes

Tempo medio alla prima risposta di gruppo per categoria:

Utilizza la stessa logica della query precedente, ma restituisce il tempo medio alla prima risposta dei membri del dato gruppo per categoria per argomenti creati da utenti che non sono membri del dato gruppo nel periodo di tempo impostato dai parametri :start_date e :end_date. Come per la query precedente, se il parametro :group_name viene lasciato al suo valore predefinito “staff”, restituirà i tempi medi di prima risposta dello staff per argomenti regolari creati da utenti non staff.

-- [params]
-- date :start_date
-- date :end_date
-- string :group_name = staff

WITH group_response_times AS (
    SELECT
        t.category_id,
        t.id AS topic_id,
        EXTRACT(MINUTE FROM (p.created_at - t.created_at)) AS response_time_minutes,
        p.user_id AS staff_user_id,
        ROW_NUMBER() OVER (PARTITION BY t.id ORDER BY p.created_at) AS row_num
    FROM posts p
    JOIN topics t ON t.id = p.topic_id
    WHERE t.user_id NOT IN (SELECT user_id
                                FROM group_users gu JOIN groups g ON g.id = gu.group_id
                                WHERE gu.user_id > 0 AND g.name = :group_name)
        AND p.user_id IN (SELECT user_id
                              FROM group_users gu JOIN groups g ON g.id = gu.group_id
                              WHERE gu.user_id > 0 AND g.name = :group_name)
        AND t.archetype = 'regular'
        AND t.deleted_at IS NULL
        AND p.post_type = 1
        AND p.deleted_at IS NULL
        AND t.created_at BETWEEN :start_date AND :end_date
)

SELECT
    category_id,
    AVG (response_time_minutes) AS average_response_time_minutes,
    COUNT(*) AS num_topics_with_staff_responses
FROM group_response_times
WHERE row_num = 1
GROUP BY category_id

@JammyDodger, forse sostituisci la query nell’OP con le ultime due query in questo post. Inoltre, probabilmente aggiorna il titolo in qualcosa come “Tempo alla prima risposta dei membri del gruppo”.

3 Mi Piace

@simon Non vedo l’ora.

Molto apprezzato. Grazie

1 Mi Piace

No, sfortunatamente questa è una cosa nota. Un rapido aggiornamento risolve comunque. :+1:

4 Mi Piace

Questo è perfetto @simon. Apprezzo molto il tuo aiuto in questo. Solo una piccola modifica da parte nostra per avere i dati di cui abbiamo bisogno, ma penso che siamo a posto. Grazie mille :heart:

1 Mi Piace

Ciao @simon

Abbiamo installato Data Explorer e utilizzato i codici che hai condiviso. Quello che vogliamo specificamente è avere il Tempo alla prima risposta per nome di ciascun membro del gruppo. Tuttavia, la query sta inviando i tempi di risposta raggruppati per ID della categoria e non per ID utente.

Apprezzeremmo il tuo aiuto. Grazie.

Grazie per aver sollevato la questione, perché c’è un errore nelle query che ho pubblicato:

EXTRACT(MINUTE FROM (p.created_at - t.created_at)) AS response_time_minutes

Questa riga fa esattamente ciò che dice, estrae i minuti dai timestamp. Ciò significa che se un argomento è stato creato alle 12:00, poi risposto un mese dopo alle 12:05, la query calcolava un tempo di risposta di 5 minuti.

La correzione è:

EXTRACT(EPOCH FROM (p.created_at - t.created_at))/ 60 AS response_time_minutes

Le date possono essere complicate. Non posso modificare il post originale, quindi posterò le correzioni qui, poi la risposta alla tua domanda in un post separato.

@JammyDodger, ecco le nuove versioni delle 2 query nel post originale:

Tempo alla prima risposta per argomento per i membri di un gruppo

-- [params]
-- date :start_date
-- date :end_date
-- string :group_name = staff

WITH group_response_times AS (
    SELECT
        t.category_id,
        t.id AS topic_id,
        EXTRACT(EPOCH FROM (p.created_at - t.created_at)) / 60 AS response_time_minutes,
        p.user_id AS staff_user_id,
        ROW_NUMBER() OVER (PARTITION BY t.id ORDER BY p.created_at) AS row_num
    FROM posts p
    JOIN topics t ON t.id = p.topic_id
    WHERE t.user_id NOT IN (SELECT user_id
                                FROM group_users gu JOIN groups g ON g.id = gu.group_id
                                WHERE gu.user_id > 0 AND g.name = :group_name)
        AND p.user_id IN (SELECT user_id
                              FROM group_users gu JOIN groups g ON g.id = gu.group_id
                              WHERE gu.user_id > 0 AND g.name = :group_name)
        AND t.archetype = 'regular'
        AND t.deleted_at IS NULL
        AND p.post_type = 1
        AND p.deleted_at IS NULL
        AND t.created_at BETWEEN :start_date AND :end_date
)

SELECT
    category_id,
    topic_id,
    staff_user_id,
    ROUND(response_time_minutes::numeric, 2) AS response_time_minutes
FROM group_response_times
WHERE row_num = 1
ORDER BY category_id, response_time_minutes

Tempo medio alla prima risposta del gruppo per categoria

-- [params]
-- date :start_date
-- date :end_date
-- string :group_name = staff

WITH group_response_times AS (
    SELECT
        t.category_id,
        t.id AS topic_id,
        EXTRACT(EPOCH FROM (p.created_at - t.created_at)) / 60 AS response_time_minutes,
        p.user_id AS staff_user_id,
        ROW_NUMBER() OVER (PARTITION BY t.id ORDER BY p.created_at) AS row_num
    FROM posts p
    JOIN topics t ON t.id = p.topic_id
    WHERE t.user_id NOT IN (SELECT user_id
                                FROM group_users gu JOIN groups g ON g.id = gu.group_id
                                WHERE gu.user_id > 0 AND g.name = :group_name)
        AND p.user_id IN (SELECT user_id
                              FROM group_users gu JOIN groups g ON g.id = gu.group_id
                              WHERE gu.user_id > 0 AND g.name = :group_name)
        AND t.archetype = 'regular'
        AND t.deleted_at IS NULL
        AND p.post_type = 1
        AND p.deleted_at IS NULL
        AND t.created_at BETWEEN :start_date AND :end_date
)

SELECT
    category_id,
    ROUND(AVG (response_time_minutes)::numeric, 2) AS average_response_time_minutes,
    COUNT(*) AS num_topics_with_staff_responses
FROM group_response_times
WHERE row_num = 1
GROUP BY category_id
4 Mi Piace

Presumo che tu voglia il tempo medio alla prima risposta per membro del gruppo; se vuoi solo il tempo impiegato dai membri del gruppo per rispondere ai singoli argomenti, usa la versione corretta della prima query nell’OP:

-- [params]
-- date :start_date
-- date :end_date
-- string :group_name = staff

WITH group_response_times AS (
    SELECT
        t.category_id,
        t.id AS topic_id,
        EXTRACT(EPOCH FROM (p.created_at - t.created_at))/ 60 AS response_time_minutes,
        p.user_id AS staff_user_id,
        ROW_NUMBER() OVER (PARTITION BY t.id ORDER BY p.created_at) AS row_num
    FROM posts p
    JOIN topics t ON t.id = p.topic_id
    WHERE t.user_id NOT IN (SELECT user_id
                                FROM group_users gu JOIN groups g ON g.id = gu.group_id
                                WHERE gu.user_id > 0 AND g.name = :group_name)
        AND p.user_id IN (SELECT user_id
                              FROM group_users gu JOIN groups g ON g.id = gu.group_id
                              WHERE gu.user_id > 0 AND g.name = :group_name)
        AND t.archetype = 'regular'
        AND t.deleted_at IS NULL
        AND p.post_type = 1
        AND p.deleted_at IS NULL
        AND t.created_at BETWEEN :start_date AND :end_date
)

SELECT
    category_id,
    topic_id,
    staff_user_id,
    ROUND(response_time_minutes::numeric, 2) AS response_time_minutes
FROM group_response_times
WHERE row_num = 1
ORDER BY category_id, response_time_minutes

Questo ti dirà il tempo impiegato dai membri del gruppo per rispondere ai singoli argomenti. I risultati sono organizzati per categoria, ma la categoria può essere ignorata.

Non sono sicuro di quanto possano essere significativi i dati sui tempi medi di risposta per i singoli membri del gruppo. Sarei cauto nell’utilizzarli per qualsiasi tipo di valutazione delle prestazioni, poiché potrebbero penalizzare i membri del gruppo che rispondono a domande o argomenti difficili che altri membri del gruppo hanno ignorato. Tenendo conto di ciò, ecco una query che restituisce i tempi medi di risposta per i membri del gruppo e il numero di argomenti a cui sono stati il primo membro del gruppo a rispondere:

-- [params]
-- date :start_date
-- date :end_date
-- string :group_name = staff

WITH group_response_times AS (
    SELECT
        t.category_id,
        t.id AS topic_id,
        EXTRACT(EPOCH FROM (p.created_at - t.created_at))/ 60 AS response_time_minutes,
        p.user_id AS staff_user_id,
        ROW_NUMBER() OVER (PARTITION BY t.id ORDER BY p.created_at) AS row_num
    FROM posts p
    JOIN topics t ON t.id = p.topic_id
    WHERE t.user_id NOT IN (SELECT user_id
                                FROM group_users gu JOIN groups g ON g.id = gu.group_id
                                WHERE gu.user_id > 0 AND g.name = :group_name)
        AND p.user_id IN (SELECT user_id
                              FROM group_users gu JOIN groups g ON g.id = gu.group_id
                              WHERE gu.user_id > 0 AND g.name = :group_name)
        AND t.archetype = 'regular'
        AND t.deleted_at IS NULL
        AND p.post_type = 1
        AND p.deleted_at IS NULL
        AND t.created_at BETWEEN :start_date AND :end_date
)

SELECT
    staff_user_id,
    ROUND(AVG(response_time_minutes)::numeric, 2) AS average_response_time_minutes,
    COUNT(*) AS number_of_topics_responded_to
FROM group_response_times
WHERE row_num = 1
GROUP BY staff_user_id
ORDER BY average_response_time_minutes
2 Mi Piace

Grazie @simon, risposta molto utile e veloce come sempre. Lo apprezzo molto!

In realtà, il nostro obiettivo è che i nostri coach (aggiunti in uno dei gruppi) misurino il loro tempo medio di risposta. In questo modo avremo un riferimento su quanto stiamo facendo bene nel fornire supporto alla community nel discorso e garantire membri soddisfatti a lungo termine.

Ha senso. Ci sono molti dati che potrebbero essere interessanti o utili se interpretati nel modo giusto. Con le query di Data Explorer a volte temo di poter scrivere query che vengono utilizzate per generare report sulle prestazioni.

Ho fatto molto lavoro di assistenza clienti. Penso che il tempo di prima risposta sia una metrica utile, ma anche la qualità della risposta deve essere presa in considerazione.

Una cosa che le query in questo argomento non ti dicono è nulla sugli argomenti che non hanno ricevuto risposta da un membro del gruppo. Le query restituiscono solo dati sugli argomenti a cui è stata data risposta. Non sono sicuro di come aggiungere al meglio informazioni sugli argomenti senza risposta alle query.

@simon ha senso.

Grazie per aver condiviso queste informazioni. Forse questa metrica (tempo alla prima risposta) dovrebbe essere sempre supportata dall’altro report sui “Topics senza risposta”.

È possibile che quando si fa clic su un valore in questo report, questo diventi un link per mostrare un riepilogo di quei “topics che non hanno risposta”? In questo modo possiamo verificare se siamo in grado di rispondere a tutti i topics che necessitano di risposte entro un tempo specificato ed escludere quei topics che in realtà non necessitano di alcuna risposta.

Non è possibile. L’opzione migliore per ottenere collegamenti ad argomenti senza risposta potrebbe essere l’utilizzo di una query Data Explorer. Potrebbe esserci una query di esempio su Meta, ma non ne trovo una cercandola.

Un’altra opzione è installare il componente del tema Unanswered Filter: Unanswered Filter. Aggiunge una voce a discesa al menu di navigazione del sito che consente di filtrare gli elenchi di argomenti per visualizzare solo gli argomenti senza risposta.

Grazie mille @simon. Apprezzo come sempre :heart:

1 Mi Piace