Response times by month
First reply time, full resolution time, requester wait time and CSAT for the tickets solved in each month: the "Efficiency" and "Satisfaction" views of Zendesk's Support dashboard.
- Grain
- month x zendesk_account x group x channel
- Built from
- 4Raw tables
- 4Staging
- 2Core
- 1Analytics
- Reads from Zendesk
- groupticketticket_metricuser
- Ships as
- Weld and dbt SQL, open source on GitHub
1-- core.zendesk.response_times_by_month
2-- First reply time, full resolution time, requester wait time and CSAT for the
3-- tickets solved in each month: the "Efficiency" and "Satisfaction" views of
4-- Zendesk's Support dashboard.
5-- Grain: month x zendesk_account x group x channel.
6-- Depends on: core.zendesk.ticket_lifecycle
7--
8-- POPULATION: tickets solved (or closed) in the month, by their latest solve
9-- date. That matches how Explore's efficiency metrics are usually dated, and it
10-- means every ticket in a row has a finished resolution time. Unsolved tickets
11-- are in ticket_volume_by_day, not here.
12--
13-- MEDIANS do not add up. A month's median across all groups is not the average
14-- of the group medians, so never roll this table up in BI for a median. Sum the
15-- _sum_ and ticket columns and divide for a mean at any level; for a median at a
16-- coarser grain, query ticket_lifecycle directly. Medians use APPROX_QUANTILES,
17-- which is approximate on large inputs.
18--
19-- CSAT is dated on the solve month as well: the rating on the ticket carries no
20-- timestamp of its own. csat_score = good / (good + bad), Zendesk's formula.
21
22WITH solved AS (
23 SELECT *
24 FROM {{core.zendesk.ticket_lifecycle}}
25 WHERE is_solved
26 AND resolved_date IS NOT NULL
27)
28
29SELECT
30 DATE_TRUNC(resolved_date, MONTH) AS month,
31 zendesk_account,
32 group_id,
33 ANY_VALUE(group_name) AS group_name,
34 channel,
35
36 COUNT(*) AS tickets_solved,
37 COUNTIF(first_reply_minutes_calendar IS NOT NULL) AS tickets_with_first_reply,
38 COUNTIF(is_one_touch) AS one_touch_tickets,
39 SAFE_DIVIDE(COUNTIF(is_one_touch), COUNT(*)) AS one_touch_rate,
40 COUNTIF(is_two_touch) AS two_touch_tickets,This model and the 6 it depends on. Deploy them together; refs like {{staging.…}} resolve to the matching folders in Weld, and the dbt view uses source() and ref().
How it counts. And where it stops.
POPULATION: tickets solved (or closed) in the month, by their latest solve date. That matches how Explore's efficiency metrics are usually dated, and it means every ticket in a row has a finished resolution time. Unsolved tickets are in ticket_volume_by_day, not here. MEDIANS do not add up. A month's median across all groups is not the average of the group medians, so never roll this table up in BI for a median. Sum the _sum_ and ticket columns and divide for a mean at any level; for a median at a coarser grain, query ticket_lifecycle directly. Medians use APPROX_QUANTILES, which is approximate on large inputs. CSAT is dated on the solve month as well: the rating on the ticket carries no timestamp of its own. csat_score = good / (good + bad), Zendesk's formula.
Raw tables it reads
- raw.zendesk.group
- raw.zendesk.ticket
- raw.zendesk.ticket_metric
- raw.zendesk.user
More Zendesk models
Put Zendesk in front
of your agents.
Connect Zendesk, deploy the models, and ask questions in Claude, Cursor or ChatGPT. Free for 14 days, no credit card.