简体   繁体   中英

Unique constraint on nested one-to-many relationship

Suppose I'm trying to represent three types of things -- grandparent, parents, and children. There's a one-to-many relationship between grandparents and parents, and a one-to-many relationship between parents and children. Parents that share a grandparent must have a unique name. The same goes for children, as all children that share a grandparent must have a unique name.

Here's an example schema:

CREATE TABLE grandparent (
  grandparentid TEXT PRIMARY KEY,
  uniquefield1 TEXT NOT NULL
);

CREATE TABLE parent (
  parentid TEXT PRIMARY KEY,
  grandparentid TEXT REFERENCES grandparent,
  name TEXT NOT NULL,
  uniquefield2 TEXT NOT NULL,
  UNIQUE (grandparentid, name)
);

CREATE TABLE child (
  childid TEXT PRIMARY KEY,
  grandparentid TEXT REFERENCES grandparent,
  parentid TEXT REFERENCES parent,
  name TEXT NOT NULL,
  uniquefield3 TEXT NOT NULL,
  UNIQUE (grandparentid, name)
);

I'm trying to come up with something that removes the need for the grandparentid field in the child table, because I don't want to get into a situation where it disagrees with the contents of the parentid field. However, I can't just remove it (to the best of my knowledge) because I still need a unique constraint on the pair of grandparentid and name .

Also worth noting is that each generation has unique information. It's a bit of a contrived example, because the actual use case is domain-specific and would just obfuscate the problem.

You need to avoid the redundancy that is not controlled by the database but by your app. A single bug in your app can store discrepancies in the data that it would be hard to resolve. Redundancy is OK if it's properly controlled.

You need to include the grandparentid column in the child table to ensure uniqueness of the name column in the subset. Now, the key aspect to consider is that you need a composite key in the parent table that can be referenced from the child table. This way you will be able to enforce the uniqueness in the child table and make sure the redundancy is always validated by the database.

For example:

create table grandparent (
  grandparentid text primary key,
  uniquefield1 text not null
);

create table parent (
  parentid text not null,
  grandparentid text not null references grandparent (grandparentid),
  name text not null,
  uniquefield2 text not null,
  unique (parentid, grandparentid), -- added this key
  unique (grandparentid, name)
);

create table child (
  childid text primary key,
  grandparentid text not null,
  parentid text not null,
  name text not null,
  uniquefield3 text not null,
  unique (grandparentid, name),
  foreign key (parentid, grandparentid) 
    references parent (parentid, grandparentid)
);

Pay attention to the last line:

  foreign key (parentid, grandparentid) 
     references parent (parentid, grandparentid)

This foreign key references a unique constraint in the parent table.

Using this structure you won't be able to insert a wrong combination of grandparentid and parentid . The database just won't have it.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM