SQL Pattern Library
30+ named SQL patterns against the contract data model. Each with a rationale, a query, and the gotchas worth knowing.
How to read this
Patterns are grouped by entity. Each entry has:
- What it answers — the business question.
- The query — copy-paste ready (Postgres dialect; trivially portable).
- Notes — gotchas, dialect variations, when to materialize as a mart.
These patterns assume the schema from chapter 01. Substitute table names as needed for your variant.
A · Agreements & renewals
A1. Renewals due in next N days
Answers: which agreements end soon enough to warrant action.
SELECT
a.agreement_id, s.canonical_name AS supplier,
a.current_term_end,
a.current_term_end - CURRENT_DATE AS days_until_renewal
FROM agreements a
JOIN suppliers s ON s.supplier_id = a.supplier_id
WHERE a.customer_id = 'cust_acme'
AND a.status = 'active'
AND a.current_term_end BETWEEN CURRENT_DATE
AND CURRENT_DATE + INTERVAL '90 days'
ORDER BY days_until_renewal;
A2. Renewals with notice deadlines
Answers: when does the customer need to give notice to cancel.
WITH renewal_obligations AS (
SELECT
agreement_id,
(value->>'notice_period_days')::INT AS notice_days,
(value->>'auto_renew')::BOOLEAN AS auto_renew
FROM obligations
WHERE obligation_type = 'renewal_notice' AND status != 'superseded'
)
SELECT
a.agreement_id, s.canonical_name,
a.current_term_end,
ro.notice_days,
a.current_term_end - INTERVAL '1 day' * COALESCE(ro.notice_days, 60) AS notice_deadline,
ro.auto_renew
FROM agreements a
JOIN suppliers s ON s.supplier_id = a.supplier_id
LEFT JOIN renewal_obligations ro ON ro.agreement_id = a.agreement_id
WHERE a.status = 'active'
AND a.current_term_end BETWEEN CURRENT_DATE AND CURRENT_DATE + INTERVAL '120 days'
ORDER BY notice_deadline;
A3. Auto-renew agreements about to renew silently
SELECT a.agreement_id, s.canonical_name, a.current_term_end
FROM agreements a
JOIN suppliers s ON s.supplier_id = a.supplier_id
JOIN obligations o
ON o.agreement_id = a.agreement_id
AND o.obligation_type = 'renewal_notice'
AND (o.value->>'auto_renew')::BOOLEAN = true
WHERE a.status = 'active'
AND a.current_term_end BETWEEN CURRENT_DATE AND CURRENT_DATE + INTERVAL '30 days';
A4. Latest amendment per agreement
SELECT a.agreement_id,
MAX(d.ingested_at) AS latest_amendment_at
FROM agreements a
JOIN document_agreement_links dal ON dal.agreement_id = a.agreement_id
JOIN documents d ON d.document_id = dal.document_id
WHERE dal.role = 'amendment'
GROUP BY a.agreement_id;
A5. Agreements expiring without SOWs
SELECT a.agreement_id, s.canonical_name, a.current_term_end
FROM agreements a
JOIN suppliers s ON s.supplier_id = a.supplier_id
WHERE a.current_term_end <= CURRENT_DATE + INTERVAL '60 days'
AND a.status = 'active'
AND NOT EXISTS (
SELECT 1 FROM document_agreement_links dal
WHERE dal.agreement_id = a.agreement_id AND dal.role = 'sow'
);
B · Documents & provenance
B1. Latest extraction per document
SELECT DISTINCT ON (e.document_id)
e.extraction_id, e.document_id, e.model_version, e.extracted_at
FROM extractions e
ORDER BY e.document_id, e.extracted_at DESC, e.model_version DESC;
B2. Orphaned amendments (no master MSA)
SELECT d.document_id, d.source_uri, d.ingested_at
FROM documents d
WHERE d.doc_class = 'amendment'
AND NOT EXISTS (
SELECT 1 FROM document_agreement_links dal
WHERE dal.document_id = d.document_id
);
B3. Documents not yet extracted with current model
SELECT d.document_id, d.doc_class, d.ingested_at
FROM documents d
LEFT JOIN extractions e
ON e.document_id = d.document_id
AND e.model_version = 'extract-v4.2.1'
WHERE e.extraction_id IS NULL
AND d.customer_id = 'cust_acme'
ORDER BY d.ingested_at;
B4. Documents with confidence below threshold
SELECT e.document_id, e.fields->'effective_date'->>'confidence' AS conf,
d.doc_class
FROM extractions e
JOIN documents d ON d.document_id = e.document_id
WHERE e.model_version = 'extract-v4.2.1'
AND (e.fields->'effective_date'->>'confidence')::FLOAT < 0.85
ORDER BY conf;
B5. Full document trail for an agreement
SELECT dal.role, d.doc_class, d.document_id, d.ingested_at, d.source_uri
FROM document_agreement_links dal
JOIN documents d ON d.document_id = dal.document_id
WHERE dal.agreement_id = 'agr_acme_msa_2020'
ORDER BY d.ingested_at;
C · Obligations
C1. Current obligations (latest extraction per agreement+type)
SELECT DISTINCT ON (o.agreement_id, o.obligation_type)
o.*
FROM obligations o
WHERE o.status != 'superseded'
ORDER BY o.agreement_id, o.obligation_type,
o.extracted_at DESC, o.model_version DESC;
C2. Upcoming due obligations
SELECT a.agreement_id, s.canonical_name, o.obligation_type, o.value, o.due_at,
o.due_at - CURRENT_DATE AS days_until_due
FROM obligations o
JOIN agreements a ON a.agreement_id = o.agreement_id
JOIN suppliers s ON s.supplier_id = a.supplier_id
WHERE o.status = 'pending'
AND o.due_at BETWEEN CURRENT_DATE AND CURRENT_DATE + INTERVAL '60 days'
ORDER BY o.due_at;
C3. Obligations missing required fields
Quality check: payment obligations should have amount and due_at.
SELECT o.obligation_id, o.agreement_id, o.value
FROM obligations o
WHERE o.obligation_type = 'payment'
AND (o.value IS NULL
OR o.value->>'amount' IS NULL
OR o.due_at IS NULL);
C4. Agreements without an indemnification clause
SELECT a.agreement_id, s.canonical_name
FROM agreements a
JOIN suppliers s ON s.supplier_id = a.supplier_id
WHERE a.agreement_type = 'master_service_agreement'
AND NOT EXISTS (
SELECT 1 FROM obligations o
WHERE o.agreement_id = a.agreement_id
AND o.obligation_type = 'indemnification'
AND o.status != 'superseded'
);
C5. Liability caps below a threshold
SELECT a.agreement_id, s.canonical_name,
(o.value->>'cap_amount')::NUMERIC AS cap_amount
FROM obligations o
JOIN agreements a ON a.agreement_id = o.agreement_id
JOIN suppliers s ON s.supplier_id = a.supplier_id
WHERE o.obligation_type = 'liability_cap'
AND o.status != 'superseded'
AND (o.value->>'cap_amount')::NUMERIC < 100000;
D · Suppliers & rollups
D1. Supplier hierarchy (root parent per supplier)
WITH RECURSIVE chain AS (
SELECT supplier_id, supplier_id AS root_id, 0 AS depth
FROM suppliers WHERE parent_supplier_id IS NULL
UNION ALL
SELECT s.supplier_id, c.root_id, c.depth + 1
FROM suppliers s JOIN chain c ON c.supplier_id = s.parent_supplier_id
)
SELECT supplier_id, root_id, depth FROM chain;
D2. Supplier consolidation candidates (similar names)
Suppliers within trigram similarity threshold of each other; surfaced for human review.
SELECT s1.supplier_id AS a_id, s1.canonical_name AS a_name,
s2.supplier_id AS b_id, s2.canonical_name AS b_name,
similarity(s1.canonical_name, s2.canonical_name) AS sim
FROM suppliers s1
JOIN suppliers s2
ON s1.customer_id = s2.customer_id
AND s1.supplier_id < s2.supplier_id
AND s1.canonical_name % s2.canonical_name -- pg_trgm operator
WHERE similarity(s1.canonical_name, s2.canonical_name) > 0.75
ORDER BY sim DESC;
D3. Spend per supplier (rolled up to parent)
See chapter 06 §operations.
D4. Suppliers with no spend but active agreements
SELECT s.supplier_id, s.canonical_name, a.agreement_id, a.effective_date
FROM suppliers s
JOIN agreements a ON a.supplier_id = s.supplier_id AND a.status = 'active'
WHERE NOT EXISTS (
SELECT 1 FROM spend sp
WHERE sp.supplier_id = s.supplier_id
AND sp.accrued_at >= a.effective_date
);
E · Spend
E1. Off-contract spend per supplier
SELECT s.supplier_id, sp.canonical_name,
SUM(s.amount) AS off_contract_total,
s.currency
FROM spend s
JOIN suppliers sp ON sp.supplier_id = s.supplier_id
LEFT JOIN agreements a
ON a.supplier_id = s.supplier_id
AND a.status = 'active'
AND s.accrued_at BETWEEN a.effective_date AND COALESCE(a.current_term_end, '9999-12-31')
WHERE a.agreement_id IS NULL
AND s.customer_id = 'cust_acme'
GROUP BY s.supplier_id, sp.canonical_name, s.currency
ORDER BY off_contract_total DESC;
E2. Off-contract subcategorized
Distinguish "no agreement ever" from "agreement expired."
WITH off_contract AS (
SELECT s.*
FROM spend s
LEFT JOIN agreements a
ON a.supplier_id = s.supplier_id
AND a.status = 'active'
AND s.accrued_at BETWEEN a.effective_date AND COALESCE(a.current_term_end, '9999-12-31')
WHERE a.agreement_id IS NULL
)
SELECT
oc.supplier_id,
CASE
WHEN EXISTS (SELECT 1 FROM agreements a2 WHERE a2.supplier_id = oc.supplier_id) THEN 'expired_agreement'
ELSE 'no_agreement'
END AS subcategory,
SUM(oc.amount) AS total
FROM off_contract oc
GROUP BY oc.supplier_id, subcategory;
E3. Spend trend by month
SELECT
DATE_TRUNC('month', s.accrued_at) AS month,
SUM(s.amount) AS total_spend
FROM spend s
WHERE s.customer_id = 'cust_acme'
AND s.currency = 'USD'
GROUP BY 1
ORDER BY 1;
E4. Top suppliers by spend in FY
SELECT s.canonical_name, SUM(sp.amount) AS fy_spend
FROM spend sp
JOIN suppliers s ON s.supplier_id = sp.supplier_id
WHERE sp.customer_id = 'cust_acme'
AND sp.accrued_at >= '2025-07-01' AND sp.accrued_at < '2026-07-01'
GROUP BY s.canonical_name
ORDER BY fy_spend DESC
LIMIT 20;
F · Quality & auditability
F1. Extraction confidence distribution
Reliability-diagram input.
SELECT
WIDTH_BUCKET((fields->'effective_date'->>'confidence')::FLOAT, 0, 1, 10) AS bucket,
COUNT(*) AS n
FROM extractions
WHERE model_version = 'extract-v4.2.1'
GROUP BY bucket
ORDER BY bucket;
F2. Documents where extraction differed between two model versions
SELECT e1.document_id,
e1.fields->'effective_date'->>'value' AS v_old,
e2.fields->'effective_date'->>'value' AS v_new
FROM extractions e1
JOIN extractions e2
ON e1.document_id = e2.document_id
WHERE e1.model_version = 'extract-v4.1.0'
AND e2.model_version = 'extract-v4.2.1'
AND COALESCE(e1.fields->'effective_date'->>'value', '') !=
COALESCE(e2.fields->'effective_date'->>'value', '');
F3. Audit trail for a supplier
SELECT raw_supplier_name, canonical_name, resolution_method, confidence, resolved_at
FROM supplier_name_resolutions snr
JOIN suppliers s ON s.supplier_id = snr.resolved_supplier_id
WHERE snr.customer_id = 'cust_acme'
AND s.canonical_name = 'Acme Corp'
ORDER BY snr.resolved_at DESC;
F4. dbt test patterns
See chapter 09 for the test taxonomy.