0

I'm trying to figure out which pattern (if any) might describe the problem I'm facing when designing the database for a club membership management system. I require help in identifying the pattern (if one exists) or some pointers of what considerations I need to make in order to make some headway.

Members are a main entity, with some information such as contact details on them. Members can have central functions at the club, ie be the treasurer or commodore etc.

In order to model the club's top level hierarchy, I would have the ID from Members, an enumeration table "BoardMemberTypes" and a "BoardMembersType" table linking the two.

However, the Club also has sub-groups, each with their own hierarchy structure.

Every Member is part of at least one of the Subgroups, with the subgroup Role "member", and the membership type such as "active" or "passive".

Each of these structures have a few identical and a few specific roles. As an example:

  • Subgroup A has chair, vice chair, treasurer from the identical set, and "Subgroup A Technology Chair" from a list only applicable to Subgroup A
  • Subgroup B has a chair, a treasurer, and a "Specific Subgroup B 1" and "Specific Subgroup B 2" role
  • Subgoup C might have only a chair and a "Specific Subgroup C" role.

The Subgroups are the complicated bit:

Enumeration Table "Subgroup" (ID, Name)
Enumeration Table "MembershipType" (ID, Name)
Enumeration Table "MembershipFunction" (ID, Name)

First hurdle: When presenting the admin interface, I'd need to constrain MembershipFunction depending on the subgroup. I guess this could be achieved through a link table:

 SubgroupMembershipFunctions (Id, SubgroupId, MembershipFunctionId)
 e.g. (Name output after applying joins obviously)
1 Subgroup A Member
2 Subgroup A Chairman
3 Subgroup A Subgroup A Technology Chair
4 Subgroup B Member
5 Subgroup B Chairman
6 Subgroup B Specific Subgroup B 1

In theory, I could now create a table "MembersSubgroupMembershipFunctions" with MembersID, SubgroupMembershipFunctionsId

At this point, I'm still lacking the abilty to store the MembershipType (active, passive) which only really applies to the "member" entry. The end result I need would be something like this maybe

User Subgroup Type Status
Justin Case A member active
Justin Case A chairman null(?)
Justin Case B member passive
Justin Case B B 1 null(?)
Joe Bloggs A member active
Jane Doe B member active
Jane Doe C member passive
Jane Doe C vicechair null(?)

Any help, pointer or idea towards improving this design is greatly appreciated.

asked Aug 17, 2020 at 10:14
4
  • Does the membership type change with each group, or is it the same for all groups? Commented Aug 17, 2020 at 14:16
  • @bbaird It can be either - you could be "member, active" in one group, and "member, active & vicechair, null" in another group. Null because I don't know how to maintain active/passive/... for members of a subgroup otherwise. So you could be member, active in A, and member, passive in B, plus any of the other types. Commented Aug 17, 2020 at 14:41
  • That makes things clearer, thanks. I'll try to have something shortly. Commented Aug 17, 2020 at 15:00
  • Don't "over-normalize" Commented Aug 17, 2020 at 16:03

1 Answer 1

1

I don't know if there is a design pattern beyond "normalize properly", but I don't think you're too far off from a workable solution.

Given your description I don't see a need for a Subgroup entity - we can just have Groups and denote one of those as "The Board".

For specific GroupFunctions, we'll consider those to be a special case for GroupMembers, i.e. once someone is assigned to a group they can be assigned Chair/Vice Chair/Special Assistant to the Jr Vice Chair/etc. Each GroupFunction can be assigned to at most one GroupMember.

As for active/passive/etc., it's entirely possible to have one level for the Member and different levels for each Group, but you might need some transaction logic if a "passive" member cannot be an "active" member of a group. Alternately, you could derive the MembershipType for each Member based on the groups they are members of.

I'll leave the datatypes and full DDL to you (including audit tables), but this should work:

CREATE TABLE MembershipType
(
 MembershipTypeCd
 ,Name
 ,CONSTRAINT PK_MembershipType PRIMARY KEY (MembershipTypeCd)
 ,CONSTRAINT AK_MembershipType UNIQUE (Name)
);
CREATE TABLE Member
(
 MemberId
 ,MembershipTypeCd
 ,CONSTRAINT FK_Member_Has_MembershipType FOREIGN KEY (MembershipTypeCd) REFERENCES MembershipType (MembershipTypeCd)
 ,CONSTRAINT PK_Member PRIMARY KEY (MemberId)
);
CREATE TABLE MemberFunction
(
 FunctionShortName
 ,Name
 ,CONSTRAINT PK_MemberFunction PRIMARY KEY (FunctionShortName)
 ,CONSTRAINT AK_MemberFunction UNIQUE (Name)
);
CREATE TABLE Group /* A reserved keyword in most DBMS - may make sense to rename */
(
 GroupId
 ,Name
 ,CONSTRAINT PK_Group PRIMARY KEY (GroupId)
 ,CONSTRAINT AK_Group UNIQUE (Name)
);
CREATE TABLE GroupMember
(
 GroupId
 ,MemberId
 ,GroupMembershipTypeCd
 ,CONSTRAINT FK_GroupMember_Member_Of_Group FOREIGN KEY (GroupId) REFERENCES Group (GroupId)
 ,CONSTRAINT FK_GroupMember_Is_Member FOREIGN KEY (MemberId) REFERENCES Member (MemberId)
 ,CONSTRAINT FK_GroupMember_Has_MembershipType FOREIGN KEY (GroupMembershipTypeCd) REFERENCES MembershipType (MembershipTypeCd)
 ,CONSTRAINT PK_GroupMember PRIMARY KEY (GroupId, MemberId)
 ,CONSTRAINT AK_GroupMember UNIQUE (MemberId, GroupId)
)
;
CREATE TABLE GroupFunction
(
 GroupId
 ,FunctionShortName
 ,CONSTRAINT FK_GroupFunction_Available_For_Group FOREIGN KEY (GroupId) REFERENCES Group (GroupId)
 ,CONSTRAINT FK_GroupFunction_Is_MemberFunction FOREIGN KEY (FunctionShortName) REFERENCES MemberFunction (FunctionShortName)
 ,CONSTRAINT PK_GroupFunction PRIMARY KEY (GroupId, FunctionShortName)
);
CREATE TABLE GroupFunctionAssignment
(
 GroupId
 ,FunctionShortName
 ,MemberId
 ,CONSTRAINT FK_GroupFunctionAssignment_Assigned_To_GroupMember FOREIGN KEY (GroupId, MemberId) REFERENCES GroupMember (GroupId, MemberId)
 ,CONSTRAINT FK_GroupFunctionAssignment_Assigment_Of_GroupFunction FOREIGN KEY (GroupId, FunctionShortName) REFERENCES GroupFunction (GroupId, FunctionShortName)
 ,CONSTRAINT PK_GroupFunctionAssignment PRIMARY KEY (GroupId, FunctionShortName)
);

Pictures are usually easier to understand (if you are unfamiliar with IDEF1X, read this): enter image description here

answered Aug 17, 2020 at 15:54
3
  • Thanks @bbaird, this looks intriguing. I hit my head on the wall after reading the suggestion to simply classify one of the groups as the board - I should have had that idea myself. I'll fill the above with some life for testing and will then mark the reply, thanks so far! Commented Aug 17, 2020 at 18:10
  • @ExternalUse let me know if something needs to be tweaked/doesn't fit with another requirement. Commented Aug 17, 2020 at 19:08
  • Thanks a lot @bbaird, this does work with a few tiny tweaks here and there. Perfect! Commented Aug 18, 2020 at 13:56

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.