简体   繁体   中英

How to force two parent records to have same grandparent record in SQL

Here is a picture of the schema for a contrived example that demonstrates the problem I am facing.

我的架构

My question is : In SQL , how do I make sure that the parent records to Door (House and Door Blueprint) each both have the same House Blueprint parent? In other words, how do I make sure that every Door record only has one House Blueprint grandparent?

I am already using best practices for foreign keys to designate the one to many relationships. I need the Door table, because the door instance could be painted any color based on the house. I need the Door Blueprint table, because I want to track who designed the door. Also, in this contrived example, the Door Blueprint can only have a single parent House Blueprint (I know this isn't realistic, so just ignore the possibility that Door Blueprints could be used in multiple House Blueprints).

The problem I am running into is that I sometimes get Door records with a House record attached to one House Blueprint and a Door Blueprint attached to a different House Blueprint record. This should never happen. And I could probably prevent this in my record insertion logic, but that is not at the SQL level.

It makes me uneasy that I have two different paths back to House Blueprint from Door, but I don't see any other way of doing it.

I'm not really looking for a bunch of code snippets, because I can figure out the syntax myself. Rather, I'm looking for a high-level approach to solving the problem in SQL . Also, I am using SQLite3, but I imagine this problem can be solved in any RDBMS.

Thanks in advance for any help with this!

In a relational database, you'd use assertions. In a SQL database, use overlapping foreign key references to unique constraints. (Not foreign key references to candidate keys.)

create table house_blueprints (
  house_blueprint_id integer primary key
);

create table houses (
  house_id integer primary key,
  house_blueprint_id integer not null,
  foreign key (house_blueprint_id) 
    references house_blueprints (house_blueprint_id),
  unique (house_id, house_blueprint_id)
);

create table door_blueprints (
  door_blueprint_id integer primary key,
  house_blueprint_id integer not null,
  foreign key (house_blueprint_id) 
    references house_blueprints (house_blueprint_id),
  unique (door_blueprint_id, house_blueprint_id)
);

create table doors (
  door_id integer primary key,
  house_id integer not null,
  house_blueprint_id integer not null,
  foreign key (house_id, house_blueprint_id) 
    references houses (house_id, house_blueprint_id),
  door_blueprint_id integer not null,
  foreign key (door_blueprint_id, house_blueprint_id) 
    references door_blueprints (door_blueprint_id, house_blueprint_id)
);

The unique constraints aren't candidate keys, because they're not minimal. But they're necessary to provide targets for the overlapping foreign keys.

The table "doors" has one column for house_blueprint_id, and two overlapping foreign key constraints that use it. No way those foreign key constraints can have different values for house_blueprint_id.

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