Queries · q066 · Head of Risk and Payments · week 1, night 1
“How many data subject requests do we receive each month, how quickly are they resolved relative to their due date, and how many are currently open — on time or overdue?”
Fictional people at a fictional company, each played by a language-model agent. Who they are and what they are told
Week 1; shared with Rosa Van den Berg, Head of Data
An enterprise prospect sent a security and compliance questionnaire covering account security, access control, privacy requests, data retention and audit trails. Sales wants answers backed by evidence from our own systems, not by policy documents.
The manager, at the start of week 1
Subject: Evidence we need for the security/compliance questionnaire (this week's priority)
Hi Claire,
This questionnaire is going to a serious enterprise prospect, and Sales wants it backed by evidence from our own systems, not by our policy wording. Rosa and I are co-owning this, so your reports will feed both the questionnaire answers themselves and a broader readiness review Rosa's side is doing. Given you only get a handful of report slots a night, let's be selective and prioritize what a security reviewer will actually probe on. In my own words, here's what I need to know:
Given the slot constraints, please treat questions 3 and 1 as the top two for this week — those are the ones Sales says the prospect calls out by name. If we only get through three of the five, drop 5 first and fold it into next week.
One more thing: since this report touches account security and personal data, please keep the output at a safe aggregate level — no need to name individual customers or staff unless I specifically ask.
Let's sync briefly before you lock in Thursday night's batch so nothing gets wasted on a bounced or bundled request.
Thanks, Aylin
Hi Claire,
Before we hand evidence to this prospect, I'd want us to be confident the underlying records are actually solid enough to stand behind in writing. A few things from my side:
If any of these raise flags on your end, I'd rather we know before it goes into a customer-facing answer than after.
Thanks, Rosa
The analyst · week 1, night 1, request 1 of 3
Aylin flagged DSAR timeliness (#3) and access control currency (#1) as the top two priorities this week, named specifically by the prospect. I'm spending all 3 slots tonight on: (a) the DSAR timeliness report, since it's the single most-probed item and a time series fits my working style; (b) a staff access-currency snapshot (elevated/system roles by account status, including whether deactivated/suspended staff still hold grants) to start on priority #1; and (c) a foundational data-quality check Rosa asked for — audit trail volume/continuity and actor-identification completeness by month — because every later report on logging, retention, and incidents this week depends on trusting that the audit trail has no silent gaps and that actions tie back to identifiable actors. I'm deliberately not touching MFA/login-security (#2) or incidents (#4/#5) tonight per Aylin's steer to drop #5 first and prioritize #1/#3; I'll plan #2 and #4 for a later night pending Thursday's sync with Aylin. All reports are kept at aggregate level (no named individuals/tenants) per Aylin's privacy instruction.
The engineer · 1 dry run on the empty schema, then the submission
WITH months AS ( SELECT DISTINCT t0.month_start, t0.month_label FROM calendar_days t0 WHERE t0.month_start BETWEEN DATE '2023-01-01' AND DATE '2025-12-01' ) SELECT m.month_label AS month, COALESCE(r.requests_received,0) AS requests_received, COALESCE(ot.completed_on_time,0) AS completed_on_time, COALESCE(lt.completed_late,0) AS completed_late, COALESCE(nd.still_open_not_due,0) AS still_open_not_due, COALESCE(od.still_open_overdue,0) AS still_open_overdue, ROUND(avgc.avg_days_to_complete,1) AS avg_days_to_complete, ROUND(medc.median_days_to_complete,1) AS median_days_to_complete, ROUND( CASE WHEN (COALESCE(ot.completed_on_time,0)+COALESCE(lt.completed_late,0))=0 THEN NULL ELSE 100.0*COALESCE(ot.completed_on_time,0)/(COALESCE(ot.completed_on_time,0)+COALESCE(lt.completed_late,0)) END, 1) AS pct_on_time FROM months m LEFT JOIN ( SELECT DATE_TRUNC('month', t1.received_at)::date AS month_start, COUNT(*) AS requests_received FROM data_subject_requests t1 GROUP BY 1 ) r ON r.month_start = m.month_start LEFT JOIN ( SELECT DATE_TRUNC('month', t2.received_at)::date AS month_start, COUNT(*) AS completed_on_time FROM data_subject_requests t2 WHERE t2.completed_at IS NOT NULL AND t2.completed_at <= t2.due_at GROUP BY 1 ) ot ON ot.month_start = m.month_start LEFT JOIN ( SELECT DATE_TRUNC('month', t3.received_at)::date AS month_start, COUNT(*) AS completed_late FROM data_subject_requests t3 WHERE t3.completed_at IS NOT NULL AND (t3.completed_at > t3.due_at OR t3.due_at IS NULL) GROUP BY 1 ) lt ON lt.month_start = m.month_start LEFT JOIN ( SELECT DATE_TRUNC('month', t4.received_at)::date AS month_start, COUNT(*) AS still_open_not_due FROM data_subject_requests t4 WHERE t4.completed_at IS NULL AND (t4.due_at IS NULL OR t4.due_at >= DATE '2025-12-31') GROUP BY 1 ) nd ON nd.month_start = m.month_start LEFT JOIN ( SELECT DATE_TRUNC('month', t5.received_at)::date AS month_start, COUNT(*) AS still_open_overdue FROM data_subject_requests t5 WHERE t5.completed_at IS NULL AND t5.due_at < DATE '2025-12-31' GROUP BY 1 ) od ON od.month_start = m.month_start LEFT JOIN ( SELECT DATE_TRUNC('month', t6.received_at)::date AS month_start, AVG(EXTRACT(EPOCH FROM (t6.completed_at - t6.received_at))/86400.0) AS avg_days_to_complete FROM data_subject_requests t6 WHERE t6.completed_at IS NOT NULL GROUP BY 1 ) avgc ON avgc.month_start = m.month_start LEFT JOIN ( SELECT month_start, PERCENTILE_CONT(0.5) WITHIN GROUP (ORDER BY days) AS median_days_to_complete FROM ( SELECT DATE_TRUNC('month', t7.received_at)::date AS month_start, EXTRACT(EPOCH FROM (t7.completed_at - t7.received_at))/86400.0 AS days FROM data_subject_requests t7 WHERE t7.completed_at IS NOT NULL ) sub GROUP BY month_start ) medc ON medc.month_start = m.month_start ORDER BY m.month_start
“Query compiles with the expected columns. Submitting.”
“Submitted. Summary of what the query does:
- Grain: one row per calendar month (2023-01 → 2025-12), built from calendar_days so every month appears even if a measure has no matching rows.
- Measures: each computed in its own subquery grouped by the month of received_at, then left-joined back onto the month spine and COALESCEd to 0 where appropriate — requests_received, completed_on_time, completed_late, still_open_not_due, still_open_overdue, avg_days_to_complete, median_days_to_complete (via PERCENTILE_CONT), and pct_on_time.
- Completion logic: treated completed_at IS NOT NULL as "completed," per the exact on-time/late definitions given in the request, so I didn't need to branch on the table's status strings.
- Reference date: hardcoded 2025-12-31 for the open/overdue split, no CURRENT_DATE used.
This is noted in the submit note for the analyst.”
As Claire Dubois saw it, from the small dataset the agents worked on
month | requests_received | completed_on_time | completed_late | still_open_not_due | still_open_overdue | avg_days_to_complete | median_days_to_complete | pct_on_time --------+-------------------+-------------------+----------------+--------------------+--------------------+----------------------+-------------------------+------------ 2023-01 | 0 | 0 | 0 | 0 | 0 | NULL | NULL | NULL 2023-02 | 0 | 0 | 0 | 0 | 0 | NULL | NULL | NULL 2023-03 | 0 | 0 | 0 | 0 | 0 | NULL | NULL | NULL 2023-04 | 1 | 1 | 0 | 0 | 0 | 29.0 | 29.0 | 100.0 2023-05 | 3 | 1 | 1 | 0 | 1 | 22.3 | 22.3 | 50.0 2023-06 | 0 | 0 | 0 | 0 | 0 | NULL | NULL | NULL 2023-07 | 0 | 0 | 0 | 0 | 0 | NULL | NULL | NULL 2023-08 | 1 | 1 | 0 | 0 | 0 | 5.9 | 5.9 | 100.0 2023-09 | 2 | 1 | 1 | 0 | 0 | 27.0 | 27.0 | 50.0 2023-10 | 1 | 1 | 0 | 0 | 0 | 11.3 | 11.3 | 100.0 2023-11 | 1 | 1 | 0 | 0 | 0 | 9.7 | 9.7 | 100.0 2023-12 | 1 | 1 | 0 | 0 | 0 | 7.8 | 7.8 | 100.0 2024-01 | 1 | 1 | 0 | 0 | 0 | 3.5 | 3.5 | 100.0 2024-02 | 3 | 2 | 1 | 0 | 0 | 20.3 | 5.8 | 66.7 2024-03 | 2 | 2 | 0 | 0 | 0 | 12.1 | 12.1 | 100.0 2024-04 | 0 | 0 | 0 | 0 | 0 | NULL | NULL | NULL 2024-05 | 3 | 3 | 0 | 0 | 0 | 14.2 | 9.8 | 100.0 2024-06 | 4 | 4 | 0 | 0 | 0 | 6.7 | 5.0 | 100.0 2024-07 | 1 | 0 | 0 | 0 | 1 | NULL | NULL | NULL 2024-08 | 2 | 2 | 0 | 0 | 0 | 15.6 | 15.6 | 100.0 2024-09 | 0 | 0 | 0 | 0 | 0 | NULL | NULL | NULL 2024-10 | 1 | 1 | 0 | 0 | 0 | 7.5 | 7.5 | 100.0 2024-11 | 4 | 4 | 0 | 0 | 0 | 9.0 | 9.5 | 100.0 2024-12 | 2 | 2 | 0 | 0 | 0 | 10.6 | 10.6 | 100.0 2025-01 | 3 | 2 | 1 | 0 | 0 | 22.4 | 5.4 | 66.7 2025-02 | 1 | 1 | 0 | 0 | 0 | 5.1 | 5.1 | 100.0 2025-03 | 2 | 1 | 0 | 0 | 1 | 15.8 | 15.8 | 100.0 2025-04 | 1 | 1 | 0 | 0 | 0 | 19.8 | 19.8 | 100.0 2025-05 | 1 | 1 | 0 | 0 | 0 | 17.2 | 17.2 | 100.0 2025-06 | 1 | 1 | 0 | 0 | 0 | 14.8 | 14.8 | 100.0 2025-07 | 0 | 0 | 0 | 0 | 0 | NULL | NULL | NULL 2025-08 | 1 | 1 | 0 | 0 | 0 | 3.1 | 3.1 | 100.0 2025-09 | 2 | 2 | 0 | 0 | 0 | 7.9 | 7.9 | 100.0 2025-10 | 1 | 1 | 0 | 0 | 0 | 23.1 | 23.1 | 100.0 2025-11 | 0 | 0 | 0 | 0 | 0 | NULL | NULL | NULL 2025-12 | 2 | 0 | 0 | 2 | 0 | NULL | NULL | NULL (36 rows)
The memo and the queries that followed; links found by title, so inferred
Later queries that build on this report:
Changed only where the benchmark needs the same result on every system
WITH months AS ( SELECT DISTINCT t0.month_start, t0.month_label SELECT DISTINCT t0.month_start AS month_start, t0.month_label AS month_label FROM calendar_days t0 WHERE t0.month_start BETWEEN DATE '2023-01-01' AND DATE '2025-12-01')SELECT m.month_label AS month, COALESCE(r.requests_received,0) AS requests_received, COALESCE(ot.completed_on_time,0) AS completed_on_time, COALESCE(lt.completed_late,0) AS completed_late, COALESCE(nd.still_open_not_due,0) AS still_open_not_due, COALESCE(od.still_open_overdue,0) AS still_open_overdue, ROUND(avgc.avg_days_to_complete,1) AS avg_days_to_complete, ROUND(medc.median_days_to_complete,1) AS median_days_to_complete, ROUND( CASE WHEN (COALESCE(ot.completed_on_time,0)+COALESCE(lt.completed_late,0))=0 THEN NULL ELSE 100.0*COALESCE(ot.completed_on_time,0)/(COALESCE(ot.completed_on_time,0)+COALESCE(lt.completed_late,0)) END, 1) AS pct_on_time avgc.avg_days_to_complete AS avg_days_to_complete, medc.median_days_to_complete AS median_days_to_complete, CASE WHEN (COALESCE(ot.completed_on_time,0)+COALESCE(lt.completed_late,0))=0 THEN NULLELSE 100.0*COALESCE(ot.completed_on_time,0)/(COALESCE(ot.completed_on_time,0)+COALESCE(lt.completed_late,0))END AS pct_on_timeFROM months mLEFT JOIN ( SELECT DATE_TRUNC('month', t1.received_at)::date AS month_start, COUNT(*) AS requests_received SELECT CAST(DATE_TRUNC('month', t1.received_at) AS date) AS month_start, COUNT(*) AS requests_received FROM data_subject_requests t1 GROUP BY 1) r ON r.month_start = m.month_startLEFT JOIN ( SELECT DATE_TRUNC('month', t2.received_at)::date AS month_start, COUNT(*) AS completed_on_time SELECT CAST(DATE_TRUNC('month', t2.received_at) AS date) AS month_start, COUNT(*) AS completed_on_time FROM data_subject_requests t2 WHERE t2.completed_at IS NOT NULL AND t2.completed_at <= t2.due_at GROUP BY 1) ot ON ot.month_start = m.month_startLEFT JOIN ( SELECT DATE_TRUNC('month', t3.received_at)::date AS month_start, COUNT(*) AS completed_late SELECT CAST(DATE_TRUNC('month', t3.received_at) AS date) AS month_start, COUNT(*) AS completed_late FROM data_subject_requests t3 WHERE t3.completed_at IS NOT NULL AND (t3.completed_at > t3.due_at OR t3.due_at IS NULL) GROUP BY 1) lt ON lt.month_start = m.month_startLEFT JOIN ( SELECT DATE_TRUNC('month', t4.received_at)::date AS month_start, COUNT(*) AS still_open_not_due SELECT CAST(DATE_TRUNC('month', t4.received_at) AS date) AS month_start, COUNT(*) AS still_open_not_due FROM data_subject_requests t4 WHERE t4.completed_at IS NULL AND (t4.due_at IS NULL OR t4.due_at >= DATE '2025-12-31') GROUP BY 1) nd ON nd.month_start = m.month_startLEFT JOIN ( SELECT DATE_TRUNC('month', t5.received_at)::date AS month_start, COUNT(*) AS still_open_overdue SELECT CAST(DATE_TRUNC('month', t5.received_at) AS date) AS month_start, COUNT(*) AS still_open_overdue FROM data_subject_requests t5 WHERE t5.completed_at IS NULL AND t5.due_at < DATE '2025-12-31' GROUP BY 1) od ON od.month_start = m.month_startLEFT JOIN ( SELECT DATE_TRUNC('month', t6.received_at)::date AS month_start, AVG(EXTRACT(EPOCH FROM (t6.completed_at - t6.received_at))/86400.0) AS avg_days_to_complete SELECT CAST(DATE_TRUNC('month', t6.received_at) AS date) AS month_start, AVG({{seconds_between(t6.received_at, t6.completed_at)}}/86400.0) AS avg_days_to_complete FROM data_subject_requests t6 WHERE t6.completed_at IS NOT NULL GROUP BY 1) avgc ON avgc.month_start = m.month_startLEFT JOIN ( SELECT month_start, PERCENTILE_CONT(0.5) WITHIN GROUP (ORDER BY days) AS median_days_to_complete SELECT month_start, {{percentile_cont(0.5, days)}} AS median_days_to_complete FROM ( SELECT DATE_TRUNC('month', t7.received_at)::date AS month_start, EXTRACT(EPOCH FROM (t7.completed_at - t7.received_at))/86400.0 AS days SELECT CAST(DATE_TRUNC('month', t7.received_at) AS date) AS month_start, {{seconds_between(t7.received_at, t7.completed_at)}}/86400.0 AS days FROM data_subject_requests t7 WHERE t7.completed_at IS NOT NULL ) sub GROUP BY month_start) medc ON medc.month_start = m.month_startORDER BY m.month_startORDER BY m.month_start NULLS LAST, m.month_label NULLS LAST
WITH months AS ( SELECT DISTINCT t0.month_start AS month_start, t0.month_label AS month_label FROM calendar_days t0 WHERE t0.month_start BETWEEN DATE '2023-01-01' AND DATE '2025-12-01' ) SELECT m.month_label AS month, COALESCE(r.requests_received,0) AS requests_received, COALESCE(ot.completed_on_time,0) AS completed_on_time, COALESCE(lt.completed_late,0) AS completed_late, COALESCE(nd.still_open_not_due,0) AS still_open_not_due, COALESCE(od.still_open_overdue,0) AS still_open_overdue, avgc.avg_days_to_complete AS avg_days_to_complete, medc.median_days_to_complete AS median_days_to_complete, CASE WHEN (COALESCE(ot.completed_on_time,0)+COALESCE(lt.completed_late,0))=0 THEN NULL ELSE 100.0*COALESCE(ot.completed_on_time,0)/(COALESCE(ot.completed_on_time,0)+COALESCE(lt.completed_late,0)) END AS pct_on_time FROM months m LEFT JOIN ( SELECT CAST(DATE_TRUNC('month', t1.received_at) AS date) AS month_start, COUNT(*) AS requests_received FROM data_subject_requests t1 GROUP BY 1 ) r ON r.month_start = m.month_start LEFT JOIN ( SELECT CAST(DATE_TRUNC('month', t2.received_at) AS date) AS month_start, COUNT(*) AS completed_on_time FROM data_subject_requests t2 WHERE t2.completed_at IS NOT NULL AND t2.completed_at <= t2.due_at GROUP BY 1 ) ot ON ot.month_start = m.month_start LEFT JOIN ( SELECT CAST(DATE_TRUNC('month', t3.received_at) AS date) AS month_start, COUNT(*) AS completed_late FROM data_subject_requests t3 WHERE t3.completed_at IS NOT NULL AND (t3.completed_at > t3.due_at OR t3.due_at IS NULL) GROUP BY 1 ) lt ON lt.month_start = m.month_start LEFT JOIN ( SELECT CAST(DATE_TRUNC('month', t4.received_at) AS date) AS month_start, COUNT(*) AS still_open_not_due FROM data_subject_requests t4 WHERE t4.completed_at IS NULL AND (t4.due_at IS NULL OR t4.due_at >= DATE '2025-12-31') GROUP BY 1 ) nd ON nd.month_start = m.month_start LEFT JOIN ( SELECT CAST(DATE_TRUNC('month', t5.received_at) AS date) AS month_start, COUNT(*) AS still_open_overdue FROM data_subject_requests t5 WHERE t5.completed_at IS NULL AND t5.due_at < DATE '2025-12-31' GROUP BY 1 ) od ON od.month_start = m.month_start LEFT JOIN ( SELECT CAST(DATE_TRUNC('month', t6.received_at) AS date) AS month_start, AVG(CAST(EXTRACT(EPOCH FROM (t6.completed_at - t6.received_at)) AS NUMERIC(18,6))/86400.0) AS avg_days_to_complete FROM data_subject_requests t6 WHERE t6.completed_at IS NOT NULL GROUP BY 1 ) avgc ON avgc.month_start = m.month_start LEFT JOIN ( SELECT month_start, PERCENTILE_CONT(0.5) WITHIN GROUP (ORDER BY days) AS median_days_to_complete FROM ( SELECT CAST(DATE_TRUNC('month', t7.received_at) AS date) AS month_start, CAST(EXTRACT(EPOCH FROM (t7.completed_at - t7.received_at)) AS NUMERIC(18,6))/86400.0 AS days FROM data_subject_requests t7 WHERE t7.completed_at IS NOT NULL ) sub GROUP BY month_start ) medc ON medc.month_start = m.month_start ORDER BY m.month_start NULLS LAST, m.month_label NULLS LAST
WITH months AS ( SELECT DISTINCT t0.month_start AS month_start, t0.month_label AS month_label FROM calendar_days t0 WHERE t0.month_start BETWEEN DATE '2023-01-01' AND DATE '2025-12-01' ) SELECT m.month_label AS month, COALESCE(r.requests_received,0) AS requests_received, COALESCE(ot.completed_on_time,0) AS completed_on_time, COALESCE(lt.completed_late,0) AS completed_late, COALESCE(nd.still_open_not_due,0) AS still_open_not_due, COALESCE(od.still_open_overdue,0) AS still_open_overdue, avgc.avg_days_to_complete AS avg_days_to_complete, medc.median_days_to_complete AS median_days_to_complete, CASE WHEN (COALESCE(ot.completed_on_time,0)+COALESCE(lt.completed_late,0))=0 THEN NULL ELSE 100.0*COALESCE(ot.completed_on_time,0)/(COALESCE(ot.completed_on_time,0)+COALESCE(lt.completed_late,0)) END AS pct_on_time FROM months m LEFT JOIN ( SELECT CAST(DATE_TRUNC('month', t1.received_at) AS date) AS month_start, COUNT(*) AS requests_received FROM data_subject_requests t1 GROUP BY 1 ) r ON r.month_start = m.month_start LEFT JOIN ( SELECT CAST(DATE_TRUNC('month', t2.received_at) AS date) AS month_start, COUNT(*) AS completed_on_time FROM data_subject_requests t2 WHERE t2.completed_at IS NOT NULL AND t2.completed_at <= t2.due_at GROUP BY 1 ) ot ON ot.month_start = m.month_start LEFT JOIN ( SELECT CAST(DATE_TRUNC('month', t3.received_at) AS date) AS month_start, COUNT(*) AS completed_late FROM data_subject_requests t3 WHERE t3.completed_at IS NOT NULL AND (t3.completed_at > t3.due_at OR t3.due_at IS NULL) GROUP BY 1 ) lt ON lt.month_start = m.month_start LEFT JOIN ( SELECT CAST(DATE_TRUNC('month', t4.received_at) AS date) AS month_start, COUNT(*) AS still_open_not_due FROM data_subject_requests t4 WHERE t4.completed_at IS NULL AND (t4.due_at IS NULL OR t4.due_at >= DATE '2025-12-31') GROUP BY 1 ) nd ON nd.month_start = m.month_start LEFT JOIN ( SELECT CAST(DATE_TRUNC('month', t5.received_at) AS date) AS month_start, COUNT(*) AS still_open_overdue FROM data_subject_requests t5 WHERE t5.completed_at IS NULL AND t5.due_at < DATE '2025-12-31' GROUP BY 1 ) od ON od.month_start = m.month_start LEFT JOIN ( SELECT CAST(DATE_TRUNC('month', t6.received_at) AS date) AS month_start, AVG(CAST(EXTRACT(EPOCH FROM (t6.completed_at - t6.received_at)) AS NUMERIC(18,6))/86400.0) AS avg_days_to_complete FROM data_subject_requests t6 WHERE t6.completed_at IS NOT NULL GROUP BY 1 ) avgc ON avgc.month_start = m.month_start LEFT JOIN ( SELECT month_start, PERCENTILE_CONT(0.5) WITHIN GROUP (ORDER BY CAST(days AS DOUBLE PRECISION)) AS median_days_to_complete FROM ( SELECT CAST(DATE_TRUNC('month', t7.received_at) AS date) AS month_start, CAST(EXTRACT(EPOCH FROM (t7.completed_at - t7.received_at)) AS NUMERIC(18,6))/86400.0 AS days FROM data_subject_requests t7 WHERE t7.completed_at IS NOT NULL ) sub GROUP BY month_start ) medc ON medc.month_start = m.month_start ORDER BY m.month_start NULLS LAST, m.month_label NULLS LAST
WITH months AS ( SELECT DISTINCT t0.month_start AS month_start, t0.month_label AS month_label FROM calendar_days t0 WHERE t0.month_start BETWEEN DATE '2023-01-01' AND DATE '2025-12-01' ) SELECT m.month_label AS month, COALESCE(r.requests_received,0) AS requests_received, COALESCE(ot.completed_on_time,0) AS completed_on_time, COALESCE(lt.completed_late,0) AS completed_late, COALESCE(nd.still_open_not_due,0) AS still_open_not_due, COALESCE(od.still_open_overdue,0) AS still_open_overdue, avgc.avg_days_to_complete AS avg_days_to_complete, medc.median_days_to_complete AS median_days_to_complete, CASE WHEN (COALESCE(ot.completed_on_time,0)+COALESCE(lt.completed_late,0))=0 THEN NULL ELSE 100.0*COALESCE(ot.completed_on_time,0)/(COALESCE(ot.completed_on_time,0)+COALESCE(lt.completed_late,0)) END AS pct_on_time FROM months m LEFT JOIN ( SELECT CAST(DATE_TRUNC('month', t1.received_at) AS date) AS month_start, COUNT(*) AS requests_received FROM data_subject_requests t1 GROUP BY 1 ) r ON r.month_start = m.month_start LEFT JOIN ( SELECT CAST(DATE_TRUNC('month', t2.received_at) AS date) AS month_start, COUNT(*) AS completed_on_time FROM data_subject_requests t2 WHERE t2.completed_at IS NOT NULL AND t2.completed_at <= t2.due_at GROUP BY 1 ) ot ON ot.month_start = m.month_start LEFT JOIN ( SELECT CAST(DATE_TRUNC('month', t3.received_at) AS date) AS month_start, COUNT(*) AS completed_late FROM data_subject_requests t3 WHERE t3.completed_at IS NOT NULL AND (t3.completed_at > t3.due_at OR t3.due_at IS NULL) GROUP BY 1 ) lt ON lt.month_start = m.month_start LEFT JOIN ( SELECT CAST(DATE_TRUNC('month', t4.received_at) AS date) AS month_start, COUNT(*) AS still_open_not_due FROM data_subject_requests t4 WHERE t4.completed_at IS NULL AND (t4.due_at IS NULL OR t4.due_at >= DATE '2025-12-31') GROUP BY 1 ) nd ON nd.month_start = m.month_start LEFT JOIN ( SELECT CAST(DATE_TRUNC('month', t5.received_at) AS date) AS month_start, COUNT(*) AS still_open_overdue FROM data_subject_requests t5 WHERE t5.completed_at IS NULL AND t5.due_at < DATE '2025-12-31' GROUP BY 1 ) od ON od.month_start = m.month_start LEFT JOIN ( SELECT CAST(DATE_TRUNC('month', t6.received_at) AS date) AS month_start, AVG(CAST(divideDecimal(toDecimal128(dateDiff('microsecond', t6.received_at, t6.completed_at), 0), toDecimal128(1000000, 0), 6) AS Nullable(Decimal(18, 6)))/86400.0) AS avg_days_to_complete FROM data_subject_requests t6 WHERE t6.completed_at IS NOT NULL GROUP BY 1 ) avgc ON avgc.month_start = m.month_start LEFT JOIN ( SELECT month_start, quantileExactInclusive(0.5)(toFloat64(days)) AS median_days_to_complete FROM ( SELECT CAST(DATE_TRUNC('month', t7.received_at) AS date) AS month_start, CAST(divideDecimal(toDecimal128(dateDiff('microsecond', t7.received_at, t7.completed_at), 0), toDecimal128(1000000, 0), 6) AS Nullable(Decimal(18, 6)))/86400.0 AS days FROM data_subject_requests t7 WHERE t7.completed_at IS NOT NULL ) sub GROUP BY month_start ) medc ON medc.month_start = m.month_start ORDER BY m.month_start NULLS LAST, m.month_label NULLS LAST
The agents' own records, as the role play wrote them; only the personal data of the person who ran it is redacted
Report request from Claire Dubois (analyst for the Head of Risk and Payments): Title: DSAR volume and timeliness by month Question: How many data subject requests do we receive each month, how quickly are they resolved relative to their due date, and how many are currently open — on time or overdue? Grain: one row per calendar month, based on the month of data_subject_requests.received_at, across all tenants combined, from 2023-01 through 2025-12 Columns: - month (YYYY-MM) - requests_received (count with received_at in month) - completed_on_time (count with completed_at not null and completed_at <= due_at) - completed_late (count with completed_at not null and completed_at > due_at, or due_at is null) - still_open_not_due (not yet completed, due_at is null or due_at >= 2025-12-31) - still_open_overdue (not yet completed, due_at < 2025-12-31) - avg_days_to_complete (avg of completed_at - received_at in days, completed requests only) - median_days_to_complete (median of the same) - pct_on_time (completed_on_time / (completed_on_time + completed_late), rounded) Details: Source: data_subject_requests. Use 2025-12-31 as the fixed 'as of' reference date for open/overdue logic (do not use CURRENT_DATE). The catalog doesn't enumerate this table's status codes — please inspect distinct status values and treat whichever represent a finished/closed request (e.g. completed_at populated) as 'completed'; note in the report which status strings/logic you used. All tenants combined (this is a platform-wide compliance metric, not per-merchant). Order by month ascending. If total rows exceed 50 they won't here (36 months expected). Check your query with the warehouse's dry_run tool, then hand it in with submit.
dry_runWITH months AS ( SELECT DISTINCT t0.month_start, t0.month_label FROM calendar_days t0 WHERE t0.month_start BETWEEN DATE '2023-01-01' AND DATE '2025-12-01' ) SELECT m.month_label AS month, COALESCE(r.requests_received,0) AS requests_received, COALESCE(ot.completed_on_time,0) AS completed_on_time, COALESCE(lt.completed_late,0) AS completed_late, COALESCE(nd.still_open_not_due,0) AS still_open_not_due, COALESCE(od.still_open_overdue,0) AS still_open_overdue, ROUND(avgc.avg_days_to_complete,1) AS avg_days_to_complete, ROUND(medc.median_days_to_complete,1) AS median_days_to_complete, ROUND( CASE WHEN (COALESCE(ot.completed_on_time,0)+COALESCE(lt.completed_late,0))=0 THEN NULL ELSE 100.0*COALESCE(ot.completed_on_time,0)/(COALESCE(ot.completed_on_time,0)+COALESCE(lt.completed_late,0)) END, 1) AS pct_on_time FROM months m LEFT JOIN ( SELECT DATE_TRUNC('month', t1.received_at)::date AS month_start, COUNT(*) AS requests_received FROM data_subject_requests t1 GROUP BY 1 ) r ON r.month_start = m.month_start LEFT JOIN ( SELECT DATE_TRUNC('month', t2.received_at)::date AS month_start, COUNT(*) AS completed_on_time FROM data_subject_requests t2 WHERE t2.completed_at IS NOT NULL AND t2.completed_at <= t2.due_at GROUP BY 1 ) ot ON ot.month_start = m.month_start LEFT JOIN ( SELECT DATE_TRUNC('month', t3.received_at)::date AS month_start, COUNT(*) AS completed_late FROM data_subject_requests t3 WHERE t3.completed_at IS NOT NULL AND (t3.completed_at > t3.due_at OR t3.due_at IS NULL) GROUP BY 1 ) lt ON lt.month_start = m.month_start LEFT JOIN ( SELECT DATE_TRUNC('month', t4.received_at)::date AS month_start, COUNT(*) AS still_open_not_due FROM data_subject_requests t4 WHERE t4.completed_at IS NULL AND (t4.due_at IS NULL OR t4.due_at >= DATE '2025-12-31') GROUP BY 1 ) nd ON nd.month_start = m.month_start LEFT JOIN ( SELECT DATE_TRUNC('month', t5.received_at)::date AS month_start, COUNT(*) AS still_open_overdue FROM data_subject_requests t5 WHERE t5.completed_at IS NULL AND t5.due_at < DATE '2025-12-31' GROUP BY 1 ) od ON od.month_start = m.month_start LEFT JOIN ( SELECT DATE_TRUNC('month', t6.received_at)::date AS month_start, AVG(EXTRACT(EPOCH FROM (t6.completed_at - t6.received_at))/86400.0) AS avg_days_to_complete FROM data_subject_requests t6 WHERE t6.completed_at IS NOT NULL GROUP BY 1 ) avgc ON avgc.month_start = m.month_start LEFT JOIN ( SELECT month_start, PERCENTILE_CONT(0.5) WITHIN GROUP (ORDER BY days) AS median_days_to_complete FROM ( SELECT DATE_TRUNC('month', t7.received_at)::date AS month_start, EXTRACT(EPOCH FROM (t7.completed_at - t7.received_at))/86400.0 AS days FROM data_subject_requests t7 WHERE t7.completed_at IS NOT NULL ) sub GROUP BY month_start ) medc ON medc.month_start = m.month_start ORDER BY m.month_start
STATUS: COMPILES (dry run on the empty schema, no data read) COLUMNS: month, requests_received, completed_on_time, completed_late, still_open_not_due, still_open_overdue, avg_days_to_complete, median_days_to_complete, pct_on_time
submitWITH months AS ( SELECT DISTINCT t0.month_start, t0.month_label FROM calendar_days t0 WHERE t0.month_start BETWEEN DATE '2023-01-01' AND DATE '2025-12-01' ) SELECT m.month_label AS month, COALESCE(r.requests_received,0) AS requests_received, COALESCE(ot.completed_on_time,0) AS completed_on_time, COALESCE(lt.completed_late,0) AS completed_late, COALESCE(nd.still_open_not_due,0) AS still_open_not_due, COALESCE(od.still_open_overdue,0) AS still_open_overdue, ROUND(avgc.avg_days_to_complete,1) AS avg_days_to_complete, ROUND(medc.median_days_to_complete,1) AS median_days_to_complete, ROUND( CASE WHEN (COALESCE(ot.completed_on_time,0)+COALESCE(lt.completed_late,0))=0 THEN NULL ELSE 100.0*COALESCE(ot.completed_on_time,0)/(COALESCE(ot.completed_on_time,0)+COALESCE(lt.completed_late,0)) END, 1) AS pct_on_time FROM months m LEFT JOIN ( SELECT DATE_TRUNC('month', t1.received_at)::date AS month_start, COUNT(*) AS requests_received FROM data_subject_requests t1 GROUP BY 1 ) r ON r.month_start = m.month_start LEFT JOIN ( SELECT DATE_TRUNC('month', t2.received_at)::date AS month_start, COUNT(*) AS completed_on_time FROM data_subject_requests t2 WHERE t2.completed_at IS NOT NULL AND t2.completed_at <= t2.due_at GROUP BY 1 ) ot ON ot.month_start = m.month_start LEFT JOIN ( SELECT DATE_TRUNC('month', t3.received_at)::date AS month_start, COUNT(*) AS completed_late FROM data_subject_requests t3 WHERE t3.completed_at IS NOT NULL AND (t3.completed_at > t3.due_at OR t3.due_at IS NULL) GROUP BY 1 ) lt ON lt.month_start = m.month_start LEFT JOIN ( SELECT DATE_TRUNC('month', t4.received_at)::date AS month_start, COUNT(*) AS still_open_not_due FROM data_subject_requests t4 WHERE t4.completed_at IS NULL AND (t4.due_at IS NULL OR t4.due_at >= DATE '2025-12-31') GROUP BY 1 ) nd ON nd.month_start = m.month_start LEFT JOIN ( SELECT DATE_TRUNC('month', t5.received_at)::date AS month_start, COUNT(*) AS still_open_overdue FROM data_subject_requests t5 WHERE t5.completed_at IS NULL AND t5.due_at < DATE '2025-12-31' GROUP BY 1 ) od ON od.month_start = m.month_start LEFT JOIN ( SELECT DATE_TRUNC('month', t6.received_at)::date AS month_start, AVG(EXTRACT(EPOCH FROM (t6.completed_at - t6.received_at))/86400.0) AS avg_days_to_complete FROM data_subject_requests t6 WHERE t6.completed_at IS NOT NULL GROUP BY 1 ) avgc ON avgc.month_start = m.month_start LEFT JOIN ( SELECT month_start, PERCENTILE_CONT(0.5) WITHIN GROUP (ORDER BY days) AS median_days_to_complete FROM ( SELECT DATE_TRUNC('month', t7.received_at)::date AS month_start, EXTRACT(EPOCH FROM (t7.completed_at - t7.received_at))/86400.0 AS days FROM data_subject_requests t7 WHERE t7.completed_at IS NOT NULL ) sub GROUP BY month_start ) medc ON medc.month_start = m.month_start ORDER BY m.month_start
Submitted to tonight's batch. Your work on this request is done.