Start your journey into Groups data with these foundational queries. Each example builds your SQL skills while providing immediate value for your ministry.
Query Customization Required
These example queries demonstrate common patterns but may require adjustments to match your specific database schema and field names. Test thoroughly in your environment before use.
IMPORTANT: All tables in the Planning Center Groups module live in the planning_center schema. Always prefix table names with planning_center. when querying.✅ CORRECT: SELECT * FROM planning_center.groups_groups
❌ INCORRECT: SELECT * FROM groups_groups
-- See all your active groups with basic informationSELECT group_id, name, description, memberships_count, schedule, location_type_preferenceFROM planning_center.groups_groupsWHERE archived_at IS NULL -- Only active groupsORDER BY name;
-- Search for groups containing specific wordsSELECT group_id, name, description, memberships_count, created_atFROM planning_center.groups_groupsWHERE LOWER(name) LIKE '%youth%' -- Case-insensitive search OR LOWER(description) LIKE '%youth%' AND archived_at IS NULLORDER BY memberships_count DESC;
-- Find large groups that might need to splitSELECT group_id, name, memberships_count, schedule, location_type_preferenceFROM planning_center.groups_groupsWHERE memberships_count > 12 -- Groups larger than 12 AND archived_at IS NULLORDER BY memberships_count DESC;
-- See groups created in the last 90 daysSELECT group_id, name, description, memberships_count, created_atFROM planning_center.groups_groupsWHERE created_at >= CURRENT_DATE - INTERVAL '90 days' AND archived_at IS NULLORDER BY created_at DESC;
-- Get all people registered in the Groups systemSELECT person_id, permissions, created_atFROM planning_center.groups_peopleORDER BY created_at DESCLIMIT 100;
-- Find people who can lead groupsSELECT person_id, permissions, created_atFROM planning_center.groups_peopleWHERE permissions IN ('leader', 'admin') -- Adjust based on your permission typesORDER BY created_at DESC;
-- See how people are connected to groupsSELECT membership_id, person_id, group_id, role, joined_atFROM planning_center.groups_membershipsORDER BY joined_at DESCLIMIT 50;
-- People who joined groups in the last 30 daysSELECT membership_id, person_id, group_id, role, joined_atFROM planning_center.groups_membershipsWHERE joined_at >= CURRENT_DATE - INTERVAL '30 days'ORDER BY joined_at DESC;
-- See members with their group namesSELECT m.membership_id, m.person_id, m.role, m.joined_at, g.name as group_name, g.schedule, g.memberships_countFROM planning_center.groups_memberships mJOIN planning_center.groups_groups g ON m.group_id = g.group_idWHERE g.archived_at IS NULLORDER BY m.joined_at DESCLIMIT 100;
-- See events happening in the next 30 daysSELECT event_id, name, description, starts_at, ends_at, location_type_preference, virtual_location_urlFROM planning_center.groups_eventsWHERE starts_at >= CURRENT_TIMESTAMP AND starts_at <= CURRENT_TIMESTAMP + INTERVAL '30 days' AND canceled = falseORDER BY starts_at;
-- Find events with online participationSELECT event_id, name, starts_at, location_type_preference, virtual_location_urlFROM planning_center.groups_eventsWHERE virtual_location_url IS NOT NULL AND starts_at >= CURRENT_TIMESTAMPORDER BY starts_atLIMIT 20;
-- All groups started this yearSELECT group_id, name, memberships_count, created_atFROM planning_center.groups_groupsWHERE created_at >= DATE_TRUNC('year', CURRENT_DATE) AND archived_at IS NULLORDER BY created_at DESC;
-- Events for the current weekSELECT event_id, name, starts_at, DATE_PART('dow', starts_at) as day_of_week, TO_CHAR(starts_at, 'Day') as day_name, TO_CHAR(starts_at, 'HH24:MI') as start_timeFROM planning_center.groups_eventsWHERE starts_at >= DATE_TRUNC('week', CURRENT_DATE) AND starts_at < DATE_TRUNC('week', CURRENT_DATE) + INTERVAL '1 week' AND canceled = falseORDER BY starts_at;
-- Track new memberships by monthSELECT DATE_TRUNC('month', joined_at) as month, COUNT(*) as new_membershipsFROM planning_center.groups_membershipsWHERE joined_at >= CURRENT_DATE - INTERVAL '12 months'GROUP BY DATE_TRUNC('month', joined_at)ORDER BY month DESC;
-- Overview of your groups ministrySELECT COUNT(*) as total_groups, COUNT(*) FILTER (WHERE archived_at IS NULL) as active_groups, COUNT(*) FILTER (WHERE archived_at IS NOT NULL) as archived_groups, AVG(memberships_count) FILTER (WHERE archived_at IS NULL) as avg_group_size, MAX(memberships_count) FILTER (WHERE archived_at IS NULL) as largest_group, MIN(memberships_count) FILTER (WHERE archived_at IS NULL AND memberships_count > 0) as smallest_groupFROM planning_center.groups_groups;
-- How groups prefer to meetSELECT location_type_preference, COUNT(*) as group_count, AVG(memberships_count) as avg_sizeFROM planning_center.groups_groupsWHERE archived_at IS NULLGROUP BY location_type_preferenceORDER BY group_count DESC;
-- Understand your leader to member ratioSELECT g.group_id, g.name, COUNT(*) FILTER (WHERE m.role = 'leader') as leaders, COUNT(*) FILTER (WHERE m.role = 'member') as members, COUNT(*) as total_membersFROM planning_center.groups_groups gJOIN planning_center.groups_memberships m ON g.group_id = m.group_idWHERE g.archived_at IS NULLGROUP BY g.group_id, g.nameHAVING COUNT(*) > 0ORDER BY total_members DESCLIMIT 20;
-- Which days have the most eventsSELECT TO_CHAR(starts_at, 'Day') as day_name, DATE_PART('dow', starts_at) as day_number, COUNT(*) as event_countFROM planning_center.groups_eventsWHERE starts_at >= CURRENT_DATE - INTERVAL '90 days' AND canceled = falseGROUP BY day_name, day_numberORDER BY day_number;
-- Find potentially inactive groups (no events in 60 days)SELECT g.group_id, g.name, g.memberships_count, MAX(e.starts_at) as last_event_dateFROM planning_center.groups_groups gLEFT JOIN planning_center.groups_event_relationships er ON g.group_id = er.group_id AND er.relationship_type = 'Group'LEFT JOIN planning_center.groups_events e ON er.relationship_id = e.event_idWHERE g.archived_at IS NULLGROUP BY g.group_id, g.name, g.memberships_countHAVING MAX(e.starts_at) < CURRENT_DATE - INTERVAL '60 days' OR MAX(e.starts_at) IS NULLORDER BY last_event_date NULLS FIRST;