Planning Center Groups Data Model
Complete reference for Planning Center Groups tables in Parable: groups, memberships, group types, events, attendance, and how they relate.
This document provides complete documentation of the Planning Center Groups data model in Parable, including all tables, fields, and relationships.
Overview
The Groups module contains 18 entity tables and 10 relationship tables supporting small groups, classes, teams, group events, attendance tracking, enrollment management, and event RSVPs.
Visual Data Model
The diagram below shows the core entities and their relationships in the Groups module. Use it as a visual reference while exploring the detailed table definitions below.
Core Entity Relationships
Key Relationships Explained
Group Structure:
GROUP_TYPEcategorizes groups (small groups, classes, teams, etc.)GROUPs are organized by type with flexible hierarchiesMEMBERSHIPs link people to groups with roles (member, leader, owner)
Enrollment Process:
ENROLLMENTtracks join requests and approvals- Separate from
MEMBERSHIPto handle pending/requested states - Once approved, becomes an active
MEMBERSHIP
Event Management:
- Groups host
EVENTs (meetings, activities, gatherings) ATTENDANCEtracks who actually attendedRSVPs track who plans to attendEVENT_NOTEs provide additional context
Generic Relationship Pattern:
- Location association via
groups_groups_relationships(relationship_type:Location) - Campus linkage via
groups_groups_relationships(relationship_type:Campus) - Resource assignments via
groups_groups_relationships
Tagging System:
TAG_GROUPs organize related tagsTAGs enable flexible categorization across groups- Applied via relationship tables
Query Requirements
Schema Prefix
IMPORTANT: All tables in the Planning Center Groups module are in the planning_center schema. You MUST prefix all table names with planning_center. in your queries.
✅ CORRECT: SELECT * FROM planning_center.groups_groups
❌ INCORRECT: SELECT * FROM groups_groups
Row Level Security (RLS)
This database uses Row Level Security (RLS) to automatically filter data based on:
- tenant_organization_id: You only see data for your current organization
- system_status: You only see 'active' records by default
DO NOT add these filters to your WHERE clause - they are applied automatically:
- ❌
WHERE tenant_organization_id = 1(unnecessary) - ❌
WHERE system_status = 'active'(unnecessary)
The RLS policies ensure you only access data you're authorized to see, making these filters redundant and potentially causing performance issues.
Core Tables Overview
Primary Entity Tables
groups_groups- Small groups, classes, and teamsgroups_people- People who can join groupsgroups_memberships- Connections between people and groupsgroups_events- Group meetings and gatheringsgroups_attendances- Event attendance recordsgroups_rsvps- Event RSVP responses from group membersgroups_group_types- Categories for organizing groupsgroups_locations- Physical meeting placesgroups_enrollments- Sign-up and registration management
Supporting Entity Tables
groups_campuses- Campus locationsgroups_campus_groups- Links between campuses and groupsgroups_event_notes- Notes for eventsgroups_group_applications- Applications to join groupsgroups_organizations- Organization settingsgroups_owners- Group ownership informationgroups_resources- Group resourcesgroups_tags- Labels for group characteristicsgroups_tag_groups- Tag groupingsgroups_group_tags- Which tags are applied to which groups
Relationship Tables
groups_groups_relationships- Links groups to other entitiesgroups_memberships_relationships- Links memberships to related entitiesgroups_events_relationships- Links events to related entitiesgroups_attendances_relationships- Links attendances to related entitiesgroups_rsvps_relationships- Links RSVPs to events, groups, and peoplegroups_enrollments_relationships- Links enrollments to related entitiesgroups_group_applications_relationships- Links applications to related entitiesgroups_event_notes_relationships- Links event notes to related entitiesgroups_resources_relationships- Links resources to related entitiesgroups_tags_relationships- Links tags to related entities
Table Definitions
groups_groups
Small groups, classes, teams, and other group entities.
| Column | Type | Description |
|---|---|---|
id | UUID | Internal unique identifier |
group_id | VARCHAR(64) | Planning Center group ID |
archived_at | TIMESTAMP | When group was archived (NULL = active) |
chat_enabled | BOOLEAN | Whether group chat is enabled |
contact_email | VARCHAR(255) | Group contact email |
created_at | TIMESTAMP | When group was created |
description | TEXT | Group description |
description_as_plain_text | TEXT | Plain text version of group description |
events_listed | BOOLEAN | Whether events are listed publicly |
events_visibility | VARCHAR(255) | Event visibility setting |
header_image | JSONB | Group header image data |
leaders_can_search_people_database | BOOLEAN | Leader permission setting |
listed | BOOLEAN | Whether the group is publicly listed |
location_type_preference | VARCHAR(255) | 'physical' or 'virtual' |
members_are_confidential | BOOLEAN | Whether member list is kept confidential |
memberships_count | INTEGER | Current member count |
name | VARCHAR(255) | Group name |
public_church_center_web_url | VARCHAR(2048) | Public group URL |
schedule | VARCHAR(255) | Meeting schedule description |
updated_at | TIMESTAMP | When group was last updated in Planning Center |
virtual_location_url | VARCHAR(2048) | Online meeting URL |
tenant_organization_id | INTEGER | Organization identifier |
system_status | VARCHAR(50) | Data status: 'active', 'transferring', 'stale' |
system_created_at | TIMESTAMP | When record was created in Parable |
system_updated_at | TIMESTAMP | When record was last updated in Parable |
groups_people
People who can participate in groups.
| Column | Type | Description |
|---|---|---|
id | UUID | Internal unique identifier |
person_id | VARCHAR(64) | Planning Center person ID |
permissions | VARCHAR(50) | Person's permission level |
created_at | TIMESTAMP | When person was added to Groups |
tenant_organization_id | INTEGER | Organization identifier |
system_status | VARCHAR(50) | Data status |
system_created_at | TIMESTAMP | When record was created in Parable |
system_updated_at | TIMESTAMP | When record was last updated in Parable |
groups_memberships
Connections between people and groups with roles.
| Column | Type | Description |
|---|---|---|
id | UUID | Internal unique identifier |
membership_id | VARCHAR(64) | Planning Center membership ID |
joined_at | TIMESTAMP | When person joined group |
role | VARCHAR(255) | 'member' or 'leader' |
tenant_organization_id | INTEGER | Organization identifier |
system_status | VARCHAR(50) | Data status |
system_created_at | TIMESTAMP | When record was created in Parable |
system_updated_at | TIMESTAMP | When record was last updated in Parable |
Note: Group and person associations are stored in the groups_memberships_relationships table (relationship_type: Group, Person). Use that table to join memberships to groups or people.
groups_events
Group meetings, gatherings, and activities.
| Column | Type | Description |
|---|---|---|
id | UUID | Internal unique identifier |
event_id | VARCHAR(64) | Planning Center event ID |
attendance_requests_enabled | BOOLEAN | Requesting attendance responses |
automated_reminder_enabled | BOOLEAN | Auto-reminders enabled |
canceled | BOOLEAN | Cancellation status |
canceled_at | TIMESTAMP | When event was canceled |
created_at | TIMESTAMP | When event was created in Planning Center |
description | TEXT | Event description |
ends_at | TIMESTAMP | Event end time |
image | VARCHAR(2048) | Event image URL |
location_type_preference | VARCHAR(255) | 'physical' or 'virtual' |
multi_day | BOOLEAN | Spans multiple days |
name | VARCHAR(255) | Event name |
reminders_sent | BOOLEAN | Reminders have been sent |
reminders_sent_at | TIMESTAMP | When reminders were sent |
repeating | BOOLEAN | Recurring event |
starts_at | TIMESTAMP | Event start time |
updated_at | TIMESTAMP | When event was last updated in Planning Center |
virtual_location_url | VARCHAR(2048) | Online meeting URL |
visitors_count | INTEGER | Number of visitors |
tenant_organization_id | INTEGER | Organization identifier |
system_status | VARCHAR(50) | Data status |
system_created_at | TIMESTAMP | When record was created in Parable |
system_updated_at | TIMESTAMP | When record was last updated in Parable |
groups_attendances
Records of who attended which events.
| Column | Type | Description |
|---|---|---|
id | UUID | Internal unique identifier |
attendance_id | VARCHAR(64) | Planning Center attendance ID |
attended | BOOLEAN | Whether person attended |
role | VARCHAR(255) | Person's role at event |
tenant_organization_id | INTEGER | Organization identifier |
system_status | VARCHAR(50) | Data status |
system_created_at | TIMESTAMP | When record was created in Parable |
system_updated_at | TIMESTAMP | When record was last updated in Parable |
Note: Event and person associations are stored in the groups_attendances_relationships table (relationship_type: Event, Person). Use that table to join attendances to events or people.
groups_rsvps
RSVP responses for group events, tracking whether people plan to attend.
| Column | Type | Description |
|---|---|---|
id | UUID | Internal unique identifier |
rsvp_id | VARCHAR(64) | Planning Center RSVP ID |
response | VARCHAR(255) | 'yes', 'no', 'maybe', 'awaiting_response' (no reply yet — the most common value), or 'not_sent' |
tenant_organization_id | INTEGER | Organization identifier |
system_status | VARCHAR(50) | Data status |
system_created_at | TIMESTAMP | When record was created in Parable |
system_updated_at | TIMESTAMP | When record was last updated in Parable |
Note: RSVPs are linked to Events, Groups, and People through the groups_rsvps_relationships table. Use relationship joins to access the event, group, or person associated with each RSVP.
groups_group_types
Categories for organizing and configuring groups.
| Column | Type | Description |
|---|---|---|
id | UUID | Internal unique identifier |
group_type_id | VARCHAR(64) | Planning Center group type ID |
church_center_visible | BOOLEAN | Visible in Church Center |
church_center_map_visible | BOOLEAN | Show on Church Center map |
color | VARCHAR(32) | Display color |
default_group_settings | JSONB | Default settings for groups of this type |
description | TEXT | Type description |
name | TEXT | Type name |
position | INTEGER | Sort order |
public_church_center_web_url | VARCHAR(2048) | Public URL for this group type |
tenant_organization_id | INTEGER | Organization identifier |
system_status | VARCHAR(50) | Data status |
system_created_at | TIMESTAMP | When record was created in Parable |
system_updated_at | TIMESTAMP | When record was last updated in Parable |
groups_locations
Physical locations where groups meet.
| Column | Type | Description |
|---|---|---|
id | UUID | Internal unique identifier |
location_id | VARCHAR(64) | Planning Center location ID |
display_preference | VARCHAR(100) | How to display location |
full_formatted_address | VARCHAR(500) | Complete address |
latitude | DOUBLE PRECISION | GPS latitude |
longitude | DOUBLE PRECISION | GPS longitude |
name | VARCHAR(255) | Location name |
radius | INTEGER | Coverage radius |
strategy | VARCHAR(100) | Location strategy |
tenant_organization_id | INTEGER | Organization identifier |
system_status | VARCHAR(50) | Data status |
system_created_at | TIMESTAMP | When record was created in Parable |
system_updated_at | TIMESTAMP | When record was last updated in Parable |
groups_enrollments
Group enrollment and registration management.
| Column | Type | Description |
|---|---|---|
id | UUID | Internal unique identifier |
enrollment_id | VARCHAR(64) | Planning Center enrollment ID |
auto_closed | BOOLEAN | Automatically closed |
auto_closed_reason | TEXT | Why auto-closed |
date_limit | TEXT | Enrollment deadline |
date_limit_reached | BOOLEAN | Past deadline |
member_limit | INTEGER | Maximum members allowed |
member_limit_reached | BOOLEAN | At capacity |
status | TEXT | Enrollment status |
strategy | TEXT | Enrollment strategy |
tenant_organization_id | INTEGER | Organization identifier |
system_status | VARCHAR(50) | Data status |
system_created_at | TIMESTAMP | When record was created in Parable |
system_updated_at | TIMESTAMP | When record was last updated in Parable |
groups_tags
Labels for categorizing and filtering groups.
| Column | Type | Description |
|---|---|---|
id | UUID | Internal unique identifier |
tag_id | VARCHAR(64) | Planning Center tag ID |
name | VARCHAR(255) | Tag name |
position | INTEGER | Sort order |
tenant_organization_id | INTEGER | Organization identifier |
system_status | VARCHAR(50) | Data status |
system_created_at | TIMESTAMP | When record was created in Parable |
system_updated_at | TIMESTAMP | When record was last updated in Parable |
groups_tag_groups
Groupings for organizing tags.
| Column | Type | Description |
|---|---|---|
id | UUID | Internal unique identifier |
tag_group_id | VARCHAR(64) | Planning Center tag group ID |
display_publicly | BOOLEAN | Show publicly |
multiple_options_enabled | BOOLEAN | Allow multiple selections |
name | VARCHAR(255) | Group name |
position | INTEGER | Sort order |
tenant_organization_id | INTEGER | Organization identifier |
system_status | VARCHAR(50) | Data status |
system_created_at | TIMESTAMP | When record was created in Parable |
system_updated_at | TIMESTAMP | When record was last updated in Parable |
groups_campuses
Campus locations for multi-site organizations.
| Column | Type | Description |
|---|---|---|
id | UUID | Internal unique identifier |
campus_id | VARCHAR(64) | Planning Center campus ID |
name | VARCHAR(255) | Campus name |
tenant_organization_id | INTEGER | Organization identifier |
system_status | VARCHAR(50) | Data status |
system_created_at | TIMESTAMP | When record was created in Parable |
system_updated_at | TIMESTAMP | When record was last updated in Parable |
groups_group_applications
Applications to join groups requiring approval.
| Column | Type | Description |
|---|---|---|
id | UUID | Internal unique identifier |
group_application_id | VARCHAR(64) | Planning Center application ID |
applied_at | TIMESTAMP | When application was submitted |
message | TEXT | Application message |
status | VARCHAR(100) | Application status |
tenant_organization_id | INTEGER | Organization identifier |
system_status | VARCHAR(50) | Data status |
system_created_at | TIMESTAMP | When record was created in Parable |
system_updated_at | TIMESTAMP | When record was last updated in Parable |
groups_event_notes
Notes and annotations for events.
| Column | Type | Description |
|---|---|---|
id | UUID | Internal unique identifier |
event_note_id | VARCHAR(64) | Planning Center event note ID |
body | TEXT | Note content |
tenant_organization_id | INTEGER | Organization identifier |
system_status | VARCHAR(50) | Data status |
system_created_at | TIMESTAMP | When record was created in Parable |
system_updated_at | TIMESTAMP | When record was last updated in Parable |
Note: Event and person associations are stored in the groups_event_notes_relationships table. Use that table to join event notes to events or people.
groups_organizations
Organization configuration and settings.
| Column | Type | Description |
|---|---|---|
id | UUID | Internal unique identifier |
organization_id | VARCHAR(64) | Planning Center organization ID |
name | VARCHAR(255) | Organization name |
time_zone | VARCHAR(255) | Organization time zone |
tenant_organization_id | INTEGER | Organization identifier |
system_status | VARCHAR(50) | Data status |
system_created_at | TIMESTAMP | When record was created in Parable |
system_updated_at | TIMESTAMP | When record was last updated in Parable |
groups_owners
Group ownership and management information.
| Column | Type | Description |
|---|---|---|
id | UUID | Internal unique identifier |
owner_id | VARCHAR(64) | Planning Center owner ID |
avatar_url | VARCHAR(2048) | Owner avatar image URL |
first_name | VARCHAR(255) | Owner first name |
last_name | VARCHAR(255) | Owner last name |
tenant_organization_id | INTEGER | Organization identifier |
system_status | VARCHAR(50) | Data status |
system_created_at | TIMESTAMP | When record was created in Parable |
system_updated_at | TIMESTAMP | When record was last updated in Parable |
groups_resources
Resources associated with groups.
| Column | Type | Description |
|---|---|---|
id | UUID | Internal unique identifier |
resource_id | VARCHAR(64) | Planning Center resource ID |
description | TEXT | Resource description |
last_updated | TIMESTAMP | When resource was last updated |
name | VARCHAR(255) | Resource name |
type | VARCHAR(50) | Resource type |
visibility | VARCHAR(50) | Resource visibility |
tenant_organization_id | INTEGER | Organization identifier |
system_status | VARCHAR(50) | Data status |
system_created_at | TIMESTAMP | When record was created in Parable |
system_updated_at | TIMESTAMP | When record was last updated in Parable |
Note: Group type associations are stored in the groups_resources_relationships table. Use that table to join resources to group types.
groups_campus_groups
Links between campuses and groups.
| Column | Type | Description |
|---|---|---|
id | UUID | Internal unique identifier |
group_id | VARCHAR(64) | Associated group ID (direct reference) |
campus_id | VARCHAR(64) | Associated campus ID (direct reference) |
tenant_organization_id | INTEGER | Organization identifier |
system_status | VARCHAR(50) | Data status |
system_created_at | TIMESTAMP | When record was created in Parable |
system_updated_at | TIMESTAMP | When record was last updated in Parable |
groups_group_tags
Which tags are applied to which groups. This is the only table that answers
"does this group carry this tag" — groups_tags_relationships links a tag to
its TagGroup, not to a group.
| Column | Type | Description |
|---|---|---|
id | UUID | Internal unique identifier |
group_id | VARCHAR(64) | Associated group ID (direct reference) |
tag_id | VARCHAR(64) | Associated tag ID (direct reference) |
tenant_organization_id | INTEGER | Organization identifier |
system_integration_id | INTEGER | Integration source identifier |
system_status | VARCHAR(50) | Data status |
system_created_at | TIMESTAMP | When record was created in Parable |
system_updated_at | TIMESTAMP | When record was last updated in Parable |
Join groups_groups and groups_tags on tenant_organization_id and
system_integration_id alongside the ID columns; the same Planning Center ID
can belong to a different source instance.
Tag coverage is not guaranteed to exist yet. Check
groups_group_tag_coverage_view for every source instance in the query before
reading an absent row as "this group has no tags": complete = false, or no
coverage row at all, means the classification is unavailable rather than empty.
Relationship Tables
groups_groups_relationships
Links groups to related entities like types, locations, and enrollments. It does
not carry tag or campus membership: use groups_group_tags for tags and
groups_campus_groups for campuses.
| Column | Type | Description |
|---|---|---|
id | UUID | Internal unique identifier |
group_id | VARCHAR(64) | Group ID |
relationship_type | VARCHAR(50) | Type of relationship |
relationship_id | VARCHAR(64) | ID of related entity |
tenant_organization_id | INTEGER | Organization identifier |
system_status | VARCHAR(50) | Data status |
system_created_at | TIMESTAMP | When created |
system_updated_at | TIMESTAMP | Last update |
Common relationship types:
GroupType- Links to groups_group_typesLocation- Links to groups_locationsEnrollment- Links to groups_enrollments
groups_memberships_relationships
Links memberships to additional related entities.
| Column | Type | Description |
|---|---|---|
id | UUID | Internal unique identifier |
membership_id | VARCHAR(64) | Membership ID |
relationship_type | VARCHAR(50) | Type of relationship |
relationship_id | VARCHAR(64) | ID of related entity |
tenant_organization_id | INTEGER | Organization identifier |
system_status | VARCHAR(50) | Data status |
system_created_at | TIMESTAMP | When created |
system_updated_at | TIMESTAMP | Last update |
Common relationship types:
Group- Links to groups_groupsPerson- Links to groups_people
groups_events_relationships
Links events to groups and locations.
| Column | Type | Description |
|---|---|---|
id | UUID | Internal unique identifier |
event_id | VARCHAR(64) | Event ID |
relationship_type | VARCHAR(50) | Type of relationship |
relationship_id | VARCHAR(64) | ID of related entity |
tenant_organization_id | INTEGER | Organization identifier |
system_status | VARCHAR(50) | Data status |
system_created_at | TIMESTAMP | When created |
system_updated_at | TIMESTAMP | Last update |
Common relationship types:
Group- Links to groups_groupsLocation- Links to groups_locations
groups_attendances_relationships
Links attendance records to events and people.
| Column | Type | Description |
|---|---|---|
id | UUID | Internal unique identifier |
attendance_id | VARCHAR(64) | Attendance ID |
relationship_type | VARCHAR(50) | Type of relationship |
relationship_id | VARCHAR(64) | ID of related entity |
tenant_organization_id | INTEGER | Organization identifier |
system_status | VARCHAR(50) | Data status |
system_created_at | TIMESTAMP | When created |
system_updated_at | TIMESTAMP | Last update |
Common relationship types:
Event- Links to groups_eventsPerson- Links to groups_people
groups_rsvps_relationships
Links RSVPs to their associated events, groups, and people.
| Column | Type | Description |
|---|---|---|
id | UUID | Internal unique identifier |
rsvp_id | VARCHAR(64) | RSVP ID |
relationship_type | VARCHAR(255) | Type of relationship |
relationship_id | VARCHAR(64) | ID of related entity |
tenant_organization_id | INTEGER | Organization identifier |
system_status | VARCHAR(50) | Data status |
system_created_at | TIMESTAMP | When created |
system_updated_at | TIMESTAMP | Last update |
Common relationship types:
Event- Links to groups_eventsGroup- Links to groups_groupsPerson- Links to groups_people
groups_enrollments_relationships
Links enrollments to related entities.
| Column | Type | Description |
|---|---|---|
id | UUID | Internal unique identifier |
enrollment_id | VARCHAR(64) | Enrollment ID |
relationship_type | VARCHAR(50) | Type of relationship |
relationship_id | VARCHAR(64) | ID of related entity |
tenant_organization_id | INTEGER | Organization identifier |
system_status | VARCHAR(50) | Data status |
system_created_at | TIMESTAMP | When created |
system_updated_at | TIMESTAMP | Last update |
Common relationship types:
Group- Links to groups_groupsPerson- Links to groups_people
groups_group_applications_relationships
Links group applications to related entities.
| Column | Type | Description |
|---|---|---|
id | UUID | Internal unique identifier |
group_application_id | VARCHAR(64) | Group application ID |
relationship_type | VARCHAR(50) | Type of relationship |
relationship_id | VARCHAR(64) | ID of related entity |
tenant_organization_id | INTEGER | Organization identifier |
system_status | VARCHAR(50) | Data status |
system_created_at | TIMESTAMP | When created |
system_updated_at | TIMESTAMP | Last update |
Common relationship types:
Group- Links to groups_groupsPerson- Links to groups_people
groups_event_notes_relationships
Links event notes to related entities like events and people.
| Column | Type | Description |
|---|---|---|
id | UUID | Internal unique identifier |
event_note_id | VARCHAR(64) | Event note ID |
relationship_type | VARCHAR(50) | Type of relationship |
relationship_id | VARCHAR(64) | ID of related entity |
tenant_organization_id | INTEGER | Organization identifier |
system_status | VARCHAR(50) | Data status |
system_created_at | TIMESTAMP | When created |
system_updated_at | TIMESTAMP | Last update |
Common relationship types:
Event- Links to groups_eventsPerson- Links to groups_people
groups_resources_relationships
Links resources to related entities like group types.
| Column | Type | Description |
|---|---|---|
id | UUID | Internal unique identifier |
resource_id | VARCHAR(64) | Resource ID |
relationship_type | VARCHAR(50) | Type of relationship |
relationship_id | VARCHAR(64) | ID of related entity |
tenant_organization_id | INTEGER | Organization identifier |
system_status | VARCHAR(50) | Data status |
system_created_at | TIMESTAMP | When created |
system_updated_at | TIMESTAMP | Last update |
Common relationship types:
GroupType- Links to groups_group_types
groups_tags_relationships
Links tags to related entities like tag groups.
| Column | Type | Description |
|---|---|---|
id | UUID | Internal unique identifier |
tag_id | VARCHAR(64) | Tag ID |
relationship_type | VARCHAR(50) | Type of relationship |
relationship_id | VARCHAR(64) | ID of related entity |
tenant_organization_id | INTEGER | Organization identifier |
system_status | VARCHAR(50) | Data status |
system_created_at | TIMESTAMP | When created |
system_updated_at | TIMESTAMP | Last update |
Common relationship types:
TagGroup- Links to groups_tag_groups
System Fields
All tables include these system fields for data management:
tenant_organization_id- Multi-tenant organization identifiersystem_status- Data lifecycle status:transferring- Being imported from Planning Centeractive- Current active datastale- Marked for removal
system_created_at- When record was created in Parablesystem_updated_at- When record was last updated in Parable
Common Query Patterns
Finding a Person's Groups
SELECT
g.name as group_name,
g.description,
m.role,
m.joined_at
FROM planning_center.groups_memberships_relationships mr_person
JOIN planning_center.groups_memberships m
ON m.membership_id = mr_person.membership_id
JOIN planning_center.groups_memberships_relationships mr_group
ON mr_group.membership_id = m.membership_id AND mr_group.relationship_type = 'Group'
JOIN planning_center.groups_groups g
ON g.group_id = mr_group.relationship_id
WHERE mr_person.relationship_type = 'Person'
AND mr_person.relationship_id = 'PERSON_ID'
AND g.archived_at IS NULL
ORDER BY m.joined_at DESC;Getting Group Members with Roles
SELECT
g.name as group_name,
p.person_id,
m.role,
m.joined_at
FROM planning_center.groups_groups g
JOIN planning_center.groups_memberships_relationships mr
ON mr.relationship_id = g.group_id AND mr.relationship_type = 'Group'
JOIN planning_center.groups_memberships m
ON m.membership_id = mr.membership_id
JOIN planning_center.groups_memberships_relationships mr_person
ON mr_person.membership_id = m.membership_id AND mr_person.relationship_type = 'Person'
JOIN planning_center.groups_people p
ON p.person_id = mr_person.relationship_id
WHERE g.group_id = 'GROUP_ID'
ORDER BY m.role DESC, m.joined_at;Finding Events for a Group
SELECT
e.name as event_name,
e.starts_at,
e.ends_at,
e.location_type_preference,
e.canceled
FROM planning_center.groups_events e
JOIN planning_center.groups_events_relationships er
ON e.event_id = er.event_id
AND er.relationship_type = 'Group'
WHERE er.relationship_id = 'GROUP_ID'
AND e.starts_at >= CURRENT_DATE
ORDER BY e.starts_at;Tracking Event Attendance
SELECT
e.name as event_name,
e.starts_at,
COUNT(CASE WHEN a.attended = true THEN 1 END) as attended_count,
COUNT(DISTINCT a.attendance_id) as total_invited
FROM planning_center.groups_events e
LEFT JOIN planning_center.groups_attendances_relationships ar
ON ar.relationship_type = 'Event' AND ar.relationship_id = e.event_id
LEFT JOIN planning_center.groups_attendances a
ON a.attendance_id = ar.attendance_id
GROUP BY e.event_id, e.name, e.starts_at
ORDER BY e.starts_at DESC;Event RSVPs Summary
SELECT
e.name as event_name,
e.starts_at,
COUNT(CASE WHEN r.response = 'yes' THEN 1 END) as yes_count,
COUNT(CASE WHEN r.response = 'no' THEN 1 END) as no_count,
COUNT(CASE WHEN r.response = 'maybe' THEN 1 END) as maybe_count,
-- Most RSVP rows are still 'awaiting_response'; count them so the
-- buckets add up to the total.
COUNT(CASE WHEN r.response = 'awaiting_response' THEN 1 END) as awaiting_count,
COUNT(CASE WHEN r.response = 'not_sent' THEN 1 END) as not_sent_count,
COUNT(*) as total_rsvps
FROM planning_center.groups_events e
JOIN planning_center.groups_rsvps_relationships er
ON e.event_id = er.relationship_id
AND er.relationship_type = 'Event'
JOIN planning_center.groups_rsvps r
ON er.rsvp_id = r.rsvp_id
WHERE e.starts_at >= CURRENT_DATE
GROUP BY e.event_id, e.name, e.starts_at
ORDER BY e.starts_at;Finding RSVPs for a Person
SELECT
e.name as event_name,
e.starts_at,
g.name as group_name,
r.response
FROM planning_center.groups_rsvps r
JOIN planning_center.groups_rsvps_relationships er
ON r.rsvp_id = er.rsvp_id
AND er.relationship_type = 'Event'
JOIN planning_center.groups_events e
ON er.relationship_id = e.event_id
JOIN planning_center.groups_rsvps_relationships gr
ON r.rsvp_id = gr.rsvp_id
AND gr.relationship_type = 'Group'
JOIN planning_center.groups_groups g
ON gr.relationship_id = g.group_id
JOIN planning_center.groups_rsvps_relationships pr
ON r.rsvp_id = pr.rsvp_id
AND pr.relationship_type = 'Person'
WHERE pr.relationship_id = 'PERSON_ID'
AND e.starts_at >= CURRENT_DATE
ORDER BY e.starts_at;Groups by Type
SELECT
gt.name as group_type,
COUNT(DISTINCT g.group_id) as group_count,
SUM(g.memberships_count) as total_members
FROM planning_center.groups_group_types gt
LEFT JOIN planning_center.groups_groups_relationships gr
ON gt.group_type_id = gr.relationship_id
AND gr.relationship_type = 'GroupType'
LEFT JOIN planning_center.groups_groups g
ON gr.group_id = g.group_id
AND g.archived_at IS NULL
GROUP BY gt.group_type_id, gt.name, gt.position
ORDER BY gt.position;Data Integrity Rules
- Schema Qualification: Always use
planning_center.prefix for all table references - Row Level Security: RLS automatically handles multi-tenancy and status filtering - do not add manual filters
- Monetary Values: Group event fees or donations stored in cents should be divided by 100.0 for display
- Archived Groups: Use
archived_at IS NULLorarchived_atcomparisons to control visibility instead of checkingsystem_status - Direct ID Columns: Core tables such as
groups_groupsandgroups_membershipsexpose direct IDs for performance-sensitive joins
Common Mistakes to Avoid
-
Missing Schema Prefix
- ❌
FROM groups_groups - ✅
FROM planning_center.groups_groups
- ❌
-
Adding Redundant RLS Filters
- ❌
WHERE tenant_organization_id = 1 AND system_status = 'active' - ✅ Trust RLS to handle this automatically
- ❌
-
Joining Without Schema
- ❌
JOIN groups_memberships m ON ... - ✅
JOIN planning_center.groups_memberships m ON ...
- ❌
-
Reaching Group Tags Through a Relationship Table
- ❌
JOIN planning_center.groups_tags_relationships tr ON tr.relationship_id = g.group_id - ❌
JOIN planning_center.groups_groups_relationships r ON r.group_id = g.group_id AND r.relationship_type = 'Tag' - ✅
JOIN planning_center.groups_group_tags gt ON gt.group_id = g.group_id AND gt.system_integration_id = g.system_integration_id groups_tags_relationshipslinks a tag to itsTagGroup, never to a group, and the sync never emits aTagrow intogroups_groups_relationships; both return zero rows and read as "no tagged groups"
- ❌
Performance Considerations
-
Indexes: All tables have optimized indexes on:
- Primary keys and entity IDs
- Join columns and foreign keys
- Date columns for time-based queries
-
Query Optimization:
- Always use the
planning_center.schema prefix - RLS handles tenant and status filtering automatically
- Filter archived groups or attendance flags when relevant
- Consider CTEs for complex multi-join queries
- Join through the
*_relationshipstables — entity tables carry no foreign-key columns
- Always use the
Data Types and Conventions
Location Preferences
physical- In-person meetingsvirtual- Online meetings
Roles
member- Regular group memberleader- Group leader with additional permissions
RSVP Responses
yes- Person plans to attendno- Person will not attendmaybe- Person is undecided
Application Status
pending- Awaiting reviewapproved- Accepted into grouprejected- Not accepted
Next Steps
- Return to Overview for high-level understanding
- Review Basic Queries for simple examples
- Check Advanced Queries for complex analysis
- See Reporting Examples for production-ready reports
Planning Center Groups SQL Queries
Query Planning Center Groups data with SQL to understand small-group participation, track membership changes, and measure group event attendance.
Basic Planning Center Groups Queries
Foundational SQL for Planning Center Groups: list active groups, count members, and see who joined a group within a given date range.