I have a table (representing applications, but this is not really relevant for this question), and I would like to have a one-to-many parent-child relationship.
ID | Name | ParentID |
---|---|---|
1 | Parent | null |
2 | Child A | 1 |
3 | Child B | 1 |
I would also like to enforce the relationship to be one-level only, i.e. if an entry has a parent it should not be used as parent by other entries:
ID | Name | ParentID | Ok |
---|---|---|---|
1 | Parent | null | Yes |
2 | Child | 1 | No : has both parent and children |
3 | Grandchild | 2 | No : child of a child |
I was thinking of enforcing this through code, but I was wondering if there is a native way to enforce this, e.g. with some constraint.
I'm using a MySQL database, in case that's somehow relevant.
See simple example
create table test( ID int, Name varchar(20), ParentID int
,primary key (id)
,xkey int default (coalesce(ParentID,Id))
,unique key (Id,xkey)
,FOREIGN KEY (ParentId) REFERENCES test(id)
,FOREIGN KEY (ParentId,xKey) REFERENCES test(Id,xkey)
);
-- Insert root
insert into test(id,Name,ParentID) values
(1,'Parent', null)
;
select * from test;
ID | Name | ParentID | xkey |
---|---|---|---|
1 | Parent | null | 1 |
Insert child
insert into test(id,Name,ParentID) values
(2,'Child A-2', 1)
;
select * from test;
ID | Name | ParentID | xkey |
---|---|---|---|
1 | Parent | null | 1 |
2 | Child A-2 | 1 | 1 |
Main test - insert child of child
insert into test(id,Name,ParentID) values
(3,'Child A-3', 2)
;
select * from test;
Cannot add or update a child row: a foreign key constraint fails (`fiddle`.`test`, CONSTRAINT `test_ibfk_2` FOREIGN KEY (`ParentID`, `xkey`) REFERENCES `test` (`ID`, `xkey`))
We can't insert this row
ID | Name | ParentID | xkey |
---|---|---|---|
3 | Child A-3 | 2 | 2 |
Insert next root
insert into test (id,Name,ParentID) values
(4,'Child C', null)
;
select * from test;
ID | Name | ParentID | xkey |
---|---|---|---|
1 | Parent | null | 1 |
2 | Child A-2 | 1 | 1 |
4 | Child C | null | 4 |
Insert childs
insert into test (id,Name,ParentID) values
(5,'Child C-5', 4)
,(6,'Child C-6', 4)
,(7,'Child C-7', 4)
;
select * from test;
Records: 3 Duplicates: 0 Warnings: 0
ID | Name | ParentID | xkey |
---|---|---|---|
1 | Parent | null | 1 |
2 | Child A-2 | 1 | 1 |
4 | Child C | null | 4 |
5 | Child C-5 | 4 | 4 |
6 | Child C-6 | 4 | 4 |
7 | Child C-7 | 4 | 4 |