Question

Does this have a name?

I don't really know how to describe the situation, and furthermore, is this a design flaw?

T4 has a FK to T3, and to T1, but I can get to T1 by T3.

The T1, T2 refers to MUST BE THE SAME as the one referenced by T4.

Situation

Was it helpful?

Solution

Does this have a name?

Redundant Foreign Key or Redundant Reference

See here and here for a random sampling of practical use case queries relating to this (sort of) from this network.

Is this a design flaw?

Maybe? Probably? I'd certainly get a whiff of code smell if I came across it in review. Whether to take action to change it (or implement it) requires more information than is currently in the post; and should probably be done for practical reasons beyond "the internet said so."

TL;DR:

You can do it. But why would you?


As noted in comments, it's usually helpful to provide sample DDL and play with the schema to both get a sense of it for yourself and to help others respond more effectively. Take a look at this DB Fiddle and see if it accurately represents what you're trying to describe.

create table t1 (
  i int not null primary key
);
create table t2 (
  i int not null primary key
    foreign key references t1(i)
    on delete cascade
);
create table t3 (
  i int not null primary key
    foreign key references t2(i)
    on delete cascade
);
create table t4 (
  i int not null primary key
    foreign key references t3(i)
    on delete cascade
);
alter table t4
  add constraint fk_t4_t1
  foreign key (i)
  references t1(i);

As you can see, it's entirely possible to define to relationship you describe (on the platform in my fiddle at least) and even to enforce cascading relationships. However... if you were to try to apply a CASCADE action to a cyclically defined relationship, you might see this (again, depending on your platform)...

Msg 1785 Level 16 State 0 Line 1

Introducing FOREIGN KEY constraint 'fk_t4_t1' on table 't4' may cause cycles or multiple cascade paths. Specify ON DELETE NO ACTION or ON UPDATE NO ACTION, or modify other FOREIGN KEY constraints.

...which would the database engine protecting you from yourself; unless you were in some crazy bizarro DBMS like PostgreSQL where redundant CASCADE is permissible.

If you cared to visualise the materialised relations that would fit into such a model, it might look like this...

select v.v, 
       t1.i t1, 
       t2.i t2, 
       t3.i t3, 
       t4.i t4
from (values (1),(2),(3),(4),(5)) v (v)
left join t4 on t4.i = v.v
left join t3 on t3.i = v.v
left join t2 on t2.i = v.v
left join t1 on t1.i = v.v;

...which might show...

+---+----+----+----+----+
| v | t1 | t2 | t3 | t4 |
+---+----+----+----+----+
| 1 | 1  | 1  | 1  | 1  |
| 2 | 2  | 2  | 2  | 2  |
| 3 | 3  | 3  | 3  |    |
| 4 | 4  | 4  |    |    |
| 5 | 5  |    |    |    |
+---+----+----+----+----+

It's also worth noting that the preceding fiddles use and X->X->X "cross-key" style mapping (which I have seen used with reasonable effectiveness "in the wild") - although yours would more strictly be...

X->X->X
↳-----⬏

Another possible interpretation of your model is the X->Y->Z dedicated key mapping if the entities are truly distinct, as seen in this fiddle, with its own unique reaction to the conflicting cascade.

OTHER TIPS

A FK constraint says that the subrow values for a referencing table's FKs' columns have to be UNIQUE subrow values for the referenced table's corresponding columns--possibly as PK (primary key) subrow values.

Whenever T (...) references U (...) & U (...) references V (...), T (...) references V (...) for some appropriate order of columns. We describe this by saying that FK constraints are transitive. We would say that the latter FK constraint is transitive & is implied by or is a consequence of the former 2 or any longer chain of references. We don't need to declare/enforce the latter if we declare/enforce the former 2 because declaring/enforcing the former enforces the latter. Undeclared transitive FK constraints are part of designs all the time.

You seem to have T4 references T3 references T2 references T1 & T4 references T1. T4 references T1 is transitive, implied by the others. So its declaration & arrow are unnecessary/redundant. We could describe the diagram as having a redundant arrow.

If instead of T4 references T1 we had T1 references T4, that would reasonably be called a (directed) FK (foreign key) (constraint) cycle.

When there is a cycle that starts & ends with the same FK column set, a consequence is that every FK subrow value with no nulls in some table has to appear uniquely in every table under the appropriate columns. (Details for subrows with NULLs depend on FK MATCH modes.)

(In the relational model when the same set of subrows values must appear in two places--not necessarily uniquely--it is called an EQD (equality dependency) constraint.)

If FK columns are all NOT NULL in some subset of the tables then you could replace that subset by an INNER JOIN of its tables using appropriate equality of columns. You could have just one table instead.

A design with a cycle is not necessarily bad--but if all the FK targets are PK or UNIQUE NOT NULL, why wouldn't you have just one table? But cases arise where we might want to keep the cycle for clarity, symmetry, performance or whatever.

Normalization to higher NFs by decomposition always introduces these cycles. But often we then decide to change our design to let a component hold more rows than it would in the original design, and that drops one or more FKs from that component to others.

Current SQL DBMSs don't happen to allow FK cycles, although doing so would be straightforward. So typically one FK must be not declared & must be enforced by triggers. (Of course, this asymmetry counteracts symmetry that we might have sought in having separate tables.)

Licensed under: CC-BY-SA with attribution
Not affiliated with dba.stackexchange
scroll top