This is a bog-standard many to many relationship. Just put it all in a
table of Placements looking like
CommitteeCode ' references Committees
CouncillorID ' references Councillors
Role ' references RoleTypes: Chair, Sec, Vice, Ordinary etc
DateOn
DateOff
BungsPaid ' etc
You can use some fancy database coding to avoid
having more than one Chair or Vice etc in a committee; not easy in Access
although it's readily do-able in a real database platform.
As you point out, a generic table of placements rather than specific
relationships tables makes the constraints harder to define. If the
chair relationship is 1:1 and the members relationship is 1:M then
having separate tables for each relationship will make things a bit be
easier.
FWIW I think attributes in the committee tables, as the OP has it,
work well where the rule is e.g. a committee must have at least one
chair and at most one chair -- exactly one chair -- because using a
relationship table makes the 1:1 relationship more like 0..1:1, the
'fancy database coding' required to ensure a referencing table has at
least one row being truly awful in Access/Jet.
If the roles (members, chairs, etc) are in different tables, they
could all be brought together using UNION in a VIEW. I'd be tempted by
this approach in a 'more capable' DBMS, where I could use WITH CHECK
OPTION to control the constraints and perhaps INSTEAD OF triggers to
make the VIEWs updatable.
All that said, although the constraints are more complex with a single
Placements table, they are not too bad in Access because you can use
field-level and record-level Validation Rules e.g. say you could have
(up to) one Chair, one Sec, two Vice and 20 Ordinary:
CREATE TABLE Placements (
CommitteeCode INTEGER NOT NULL REFERENCES Committees (CommitteeCode),
CouncillorID INTEGER NOT NULL REFERENCES Councillors (CouncillorID),
Role VARCHAR(8) NOT NULL,
CHECK (Role IN ('Chair', 'Sec', 'Vice', 'Ordinary')),
seq INTEGER NOT NULL,
UNIQUE (CommitteeCode, CouncillorID),
UNIQUE (CommitteeCode, Role, seq),
CHECK ('T' = SWITCH (
Role IN ('Chair', 'Sec'), IIF(seq = 1, 'T', 'F'),
Role = 'Vice', IIF(seq BETWEEN 1 AND 2, 'T', 'F'),
Role = 'Ordinary', IIF(seq BETWEEN 1 AND 20, 'T', 'F')
))
)
;
I've posted as CHECK constraints for clarity but the examples here can
be replaced with Validation Rules
BTW the limits (1, 2, 20 etc) don't have to be hard wired into the
schema in this way and can be different for all committees keeping the
same king of design (DRI and Validation Rules); for an example see:
http://groups.google.com/group/microsoft.public.access/msg/1d4430dc8b50ba8f
Make up the PK on the combination of (CommitteeCode, CouncillorID) to
avoid double-counting.
Modelling the relationship table as periods (DateOn, DateOff) makes
things considerably more complex and invalidates your suggestion for
PK i.e. you'd instead need a *sequenced* primary key to allow a
councillor to be a member of the same committee during different
historical periods, no overlapping periods, etc. The combination of a
generic Placements table and valid-time states would make for a
*really* complex table!
Jamie.
--