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

Hallo @simon

Vielen Dank, dass Sie eine mögliche Lösung zum Generieren von Berichten über die Reaktionszeit des Personals pro Monat geteilt haben. Ist dieser Code noch brauchbar oder gibt es eine aktualisierte Version? Gibt es außerdem eine Möglichkeit, diesen Bericht wöchentlich statt monatlich zu erstellen? Vielen Dank

1 „Gefällt mir“

Das ist er nicht. Ehrlich gesagt, ich bin mir nicht sicher, wie er jemals funktioniert hat. Ich werde bald eine aktualisierte Version posten und dich benachrichtigen, wenn sie fertig ist.

Bearbeiten: @IreneT
Hier ist eine korrigierte Version der ursprünglichen Abfrage. Ich würde diese Abfrage ignorieren und stattdessen die anderen Abfragen betrachten, die ich in dieser Antwort gepostet habe. Lass mich wissen, wenn du Fragen zu den Abfragen hast oder Probleme beim Hinzufügen der erforderlichen Parameter zu den Abfragen hast. Beim Testen heute stelle ich fest, dass ich die Seite nach dem Speichern einer Data Explorer-Abfrage aktualisieren muss, damit die Eingabefelder für Parameter unter der Abfrage angezeigt werden. (Das ist vielleicht nur eine Eigenart auf meiner lokalen Entwicklungsumgebung.)

-- [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 "Average First Response Time",
COUNT(1) AS "Topics Responded to"
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

Was geändert wurde:

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

Ich wäre überrascht, wenn ich die alte Abfrage ohne Test geschrieben hätte. Auf jeden Fall funktioniert die aktualisierte Version jetzt wie erwartet.

Aus dem Gedächtnis: Diese Abfrage wurde für eine bestimmte Website geschrieben und war nicht für die Veröffentlichung auf Meta bestimmt. Hier sind ein paar weitere nützliche Abfragen, um Informationen über die Reaktionszeiten des Personals zu erhalten:

Zeit bis zur ersten Gruppenantwort für Themen, die innerhalb eines bestimmten Zeitraums erstellt wurden

Gibt die Zeit bis zur ersten Antwort eines Mitglieds einer bestimmten Gruppe auf “reguläre” (nicht persönliche Nachrichten) Themen zurück, die von einem Benutzer erstellt wurden, der kein Mitglied der angegebenen Gruppe ist. Der Parameter :group_name der Abfrage ist standardmäßig auf “staff” gesetzt. Mit diesem Wert erhalten Sie die Zeit bis zur ersten Antwort von Mitarbeitern. Sie können den Wert dieses Parameters ändern, um Antwortzeiten für verschiedene Gruppen zu erhalten. Zum Beispiel “customer_support”.

Beachten Sie, dass Daten technisch in der Form jjjj-mm-tt angegeben werden sollten, die Abfrage würde aber auch Daten in der Form tt-mm-jjjj akzeptieren.

-- [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

Durchschnittliche Zeit bis zur ersten Gruppenantwort pro Kategorie:

Verwendet die gleiche Logik wie die vorherige Abfrage, gibt aber die durchschnittliche Zeit bis zur ersten Antwort von Mitgliedern der angegebenen Gruppe pro Kategorie für Themen zurück, die von Benutzern erstellt wurden, die keine Mitglieder der angegebenen Gruppe sind, innerhalb des durch die Parameter :start_date und :end_date festgelegten Zeitraums. Wie bei der vorherigen Abfrage gibt die Angabe des Standardwerts “staff” für den Parameter :group_name die durchschnittlichen ersten Antwortzeiten des Personals für reguläre Themen zurück, die von Nicht-Personal-Benutzern erstellt wurden.

-- [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, vielleicht ersetze die Abfrage im OP durch die letzten beiden Abfragen in diesem Beitrag. Aktualisiere wahrscheinlich auch den Titel zu etwas wie “Zeit bis zur ersten Antwort von Gruppenmitgliedern”.

3 „Gefällt mir“

@simon Ich freue mich darauf.
Vielen Dank. Danke

1 „Gefällt mir“

Nein, das ist leider bekannt. Ein schnelles Aktualisieren behebt das Problem jedoch. :+1:

4 „Gefällt mir“

Das ist perfekt, @simon. Ich weiß deine Hilfe hier wirklich zu schätzen. Nur eine kleine Anpassung von unserer Seite, um die benötigten Daten zu erhalten, aber ich denke, wir sind gut aufgestellt. Vielen Dank :heart:

1 „Gefällt mir“

Hallo @simon

Wir haben Data Explorer installiert und die von Ihnen geteilten Codes verwendet. Was wir speziell möchten, ist die Zeit bis zur ersten Antwort nach dem Namen jedes Gruppenmitglieds. Die Abfrage sendet jedoch Antwortzeiten, die nach der Kategorie-ID und nicht nach der Benutzer-ID gruppiert sind.

Wir würden uns über Ihre Hilfe freuen. Danke.

Danke, dass Sie das ansprechen, denn es gibt einen Fehler in den Abfragen, die ich gepostet habe:

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

Diese Zeile tut genau das, was sie sagt: Sie extrahiert Minuten aus den Zeitstempeln. Das bedeutet, dass die Abfrage eine Antwortzeit von 5 Minuten berechnet hätte, wenn ein Thema um 12:00 Uhr erstellt und einen Monat später um 12:05 Uhr beantwortet worden wäre.

Die Korrektur lautet:

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

Daten können knifflig sein. Ich kann den OP nicht bearbeiten, also werde ich die Korrekturen hier posten und dann die Antwort auf Ihre Frage in einem separaten Beitrag.

@JammyDodger, hier sind neue Versionen der 2 Abfragen im OP:

Zeit bis zur ersten Antwort pro Thema für Mitglieder einer Gruppe

-- [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

Durchschnittliche Zeit bis zur ersten Gruppenantwort pro Kategorie

-- [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 „Gefällt mir“

Ich gehe davon aus, dass Sie die durchschnittliche Zeit bis zur ersten Antwort pro Gruppenmitglied wünschen. Wenn Sie nur die Zeit wünschen, die Gruppenmitglieder für die Beantwortung einzelner Themen benötigt haben, verwenden Sie die feste Version der ersten Abfrage im 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

Dies zeigt Ihnen die Zeit, die Gruppenmitglieder für die Beantwortung einzelner Themen benötigt haben. Die Ergebnisse sind nach Kategorie geordnet, aber die Kategorie kann ignoriert werden.

Ich bin mir nicht sicher, wie aussagekräftig Daten für durchschnittliche Antwortzeiten für einzelne Gruppenmitglieder sind. Ich wäre vorsichtig, sie für Leistungsüberprüfungen zu verwenden, da sie Gruppenmitgliedern, die schwierige Fragen beantworten, oder Themen, die andere Gruppenmitglieder ignoriert haben, bestrafen könnten. In diesem Sinne finden Sie hier eine Abfrage, die die durchschnittlichen Antwortzeiten für Gruppenmitglieder und die Anzahl der Themen zurückgibt, auf die sie als erstes Gruppenmitglied geantwortet haben:

-- [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 „Gefällt mir“

Danke @simon – wie immer sehr hilfreich und schnell. Ich weiß es wirklich zu schätzen!

Unser Ziel ist es tatsächlich, dass unsere Coaches (die einer der Gruppen hinzugefügt wurden) ihre durchschnittliche Antwortzeit messen können. Auf diese Weise haben wir einen Anhaltspunkt dafür, wie gut wir bei der Bereitstellung von Community-Support in Discourse abschneiden und langfristig zufriedene Mitglieder sicherstellen.

Das ergibt Sinn. Es gibt viele Daten, die interessant oder nützlich sein könnten, wenn sie richtig interpretiert werden. Bei Data Explorer-Abfragen mache ich mir manchmal Sorgen, dass ich Abfragen schreiben könnte, die zur Erstellung von Leistungsberichten verwendet werden.

Ich habe viel im Kundensupport gearbeitet. Ich glaube zwar, dass die Zeit bis zur ersten Antwort eine nützliche Metrik ist, aber die Qualität der Antwort muss ebenfalls berücksichtigt werden.

Eine Sache, die die Abfragen in diesem Thema nicht verraten, ist etwas über Themen, die keine Antwort von einem Gruppenmitglied erhalten haben. Die Abfragen geben nur Daten über Themen zurück, auf die geantwortet wurde. Ich bin mir nicht sicher, wie ich am besten Informationen über Themen ohne Antwort zu den Abfragen hinzufügen kann.

@simon das ergibt Sinn.

Danke für die Weitergabe dieser Informationen. Vielleicht sollte diese Metrik (Zeit bis zur ersten Antwort) immer durch den anderen Bericht über „Themen ohne Antwort“ ergänzt werden.

Ist es möglich, dass, wenn auf einen Wert in diesem Bericht geklickt wird, dieser ein Link ist, der eine Zusammenfassung der „Themen, die keine Antwort haben“ anzeigt? Auf diese Weise können wir überprüfen, ob wir alle Themen, die Antworten benötigen, innerhalb einer bestimmten Zeit beantworten können, und dies würde diejenigen Themen ausschließen, die wirklich überhaupt keine Antwort benötigen.

Das ist nicht möglich. Die beste Option, um Links zu unbeantworteten Themen zu erhalten, ist die Verwendung einer Data Explorer-Abfrage. Möglicherweise gibt es eine Beispielabfrage dafür auf Meta, aber ich finde keine, wenn ich danach suche.

Eine weitere Option ist die Installation der Unanswered Filter-Theme-Komponente: Unanswered Filter. Sie fügt dem Navigationsmenü der Website einen Dropdown-Eintrag hinzu, mit dem Sie Themenlisten filtern können, um nur unbeantwortete Themen anzuzeigen.

Vielen Dank, @simon. Wie immer sehr geschätzt :heart:

1 „Gefällt mir“