Reputation: 3511
I have the following tables: CREATE TABLE group_systems ( group_name, system_name, section_name, created_date, decom_date, status (Active, Deactivate) )
CREATE TABLE systems ( system_name, section_name )
A system is identified by the key (system_name, section_name). There can be dup system names but no dup section name.
In the groups table, I want to enforce the constraint that only one system in a section in a group can be active. However, because the groups table is also a history table, I can't just use the unique constraint (group_name, section_name, system_name). I have to use a check constraint that runs a subquery. There's also some additional constraints that are subqueries.
The problem is that inserting a benchmark of 100k records takes a long time (due to the subqueries).
Is it better to build another table active_systems_for_groups that references back to the group_systems table? That way, I can add the unique constraint to active_systems_for_groups that enforces only one active system per section per group and keep building complex constraints by adding more tables.
Is there a better way to handle complex check constraints?
Upvotes: 1
Views: 1803
Reputation: 47464
Since you never answered which RDBMS you're using I'll throw this out there for others who might be interested in another way to easily handle this constraint in SQL Server (2008 or later).
You can use a filtered unique index to effectively put a constraint on the number of "active" rows for a given type. As an example:
CREATE UNIQUE INDEX My_Table_active_IDX ON My_Table (some_pk) WHERE active = 1
This approach has several advantages:
Upvotes: 1
Reputation: 50990
You can enforce the "single active record" pattern in two ways:
The solution you suggest, which is to create a table that holds only the primary key values of the active records from the multiple-records-allowed table. Those values also serve as a primary key in the active records table.
Adding a column to another table that represents the objects that can have only a single active record each. In this case that would mean adding a column active_group_name to systems. This column would be a foreign key to the multiple-records-allowed table.
Which is preferable depends, in part, on whether every section is required to have an active group, whether it's common (but not required) for a section to have an active group, or whether it's only occasionally true that a section has an active group.
In the first case (required), you would use option (2) and the column could be declared NOT NULL, preserving complete normalization. In the second case (common) you would need to make the column NULLable but I'd probably still use that technique for convenience of JOINs. In the third case (occasional), I'd probably use option (1) since it might well improve performance when JOINing to get the active records.
Upvotes: 2