4

Consider the following model where a Customer should have one and only one Address and an Address should belong to one and only one Customer:

enter image description here

To implement it, as almost everybody in DB field says, Shared PK is the solution:

enter image description here

But I think it is a fake one-to-one relationship. Because nothing in terms of database relationship actually prevents deleting any row in table Address. So truely, it is 1..[0..1] not 1..1

Am I right? Is there any other way to implement a true 1..1 relation?

Update:

Why cascade delete is not a solution:

If we consider cascade delete as a solution we should put this on either of the tables. Let's say if a row is deleted from table Address, it causes corresponding row in table Customer to be deleted. it's okay but half of the solution. If a row in Customer is deleted, the corresponding row in Address should be deleted as well. This is the second half of the solution, and it obviously makes a cycle.

philipxy
  • 14,867
  • 6
  • 39
  • 83
Hans
  • 2,674
  • 4
  • 25
  • 48
  • You could implement `DELETE CASCADE` See [**HOW**](http://stackoverflow.com/questions/6260688/how-do-i-use-cascade-delete-with-sql-server) – Juan Carlos Oropeza Oct 08 '15 at 16:30
  • But you can ensure that a row in table adress is not deletable so long as the relationship (Foreign key) is set to'Restrict'. – OneTwo Oct 08 '15 at 16:31
  • @JuanCarlosOropeza Thanks for your feedback. Would you please see the update? – Hans Oct 08 '15 at 23:04
  • @OneTwo Is `Restrict` related to a special RDBMS? – Hans Oct 08 '15 at 23:05
  • 1
    IMHO it is never needed. (if it were needed, it could be one table, see @phillipsxy's answer) in most cases, you should allow homeless people, or empty houses, or people living at the same address. – wildplasser Oct 08 '15 at 23:08
  • 1
    @Hans looks like your is more like academic/philosophic question because you arent mention any RDBMS. I even considering close it to be off topic because isnt really about programming. But I will provide with other similar question I found [HERE](http://stackoverflow.com/questions/10292355/how-do-i-create-a-real-one-to-one-relationship-in-sql-server) and [HERE](http://stackoverflow.com/questions/7644156/implementing-one-to-zero-or-one-relation-in-sql-server) and [HERE](http://stackoverflow.com/questions/5112473/designing-11-and-1m-relationships-in-sql-server) – Juan Carlos Oropeza Oct 08 '15 at 23:18
  • @JuanCarlosOropeza Great catch and great addressing, thank you very much. Actually, you are right and my question is more on concept than practice. The three question/answers you mentioned are fantastic and all of them addressed my concern. Now, I am assured it is not possible to implement a true 1:1 relationship in RDBMs without fancy things like trigger. – Hans Oct 09 '15 at 02:16

7 Answers7

3

Beside my comment

  • You could implement DELETE CASCADE See HOW

I realize there is also the problem of insert.

  • You have to insert Customer first and then Address

So I think the best way if you really want a 1:1 is create a single table instead.

Customer

CustomerID
Name
Address
City
Community
  • 1
  • 1
Juan Carlos Oropeza
  • 47,252
  • 12
  • 78
  • 118
  • Don't conflate entities with rows. Entities are represented by values, not rows. Rows represent relationships. – reaanb Oct 08 '15 at 21:02
  • 2
    @reaanb for me entity is a table or a class. – Juan Carlos Oropeza Oct 08 '15 at 21:11
  • If you said table instead of entity, I might've upvoted instead of commenting, since I was thinking the same thing. However, entity is a term from conceptual data modeling and is used to denote the elements about which we record information. Equating those elements with the data structures or software artefacts used to record their data is misleading, especially when they don't effectively map one-to-one. – reaanb Oct 09 '15 at 05:51
  • 1
    @reaanb & @ JuanCarlosOropeza In ER-oriented methods an entity instance or relationship/association instance is represented by a row and an entity class/set or relationship/association class/set is represented by a table. Naked "entity"/"relationship"/"association" get used (confusingly) for instance and/or class/set. (And "relationship'' for FK.) Since *every superkey of every expression value is 1:1 with an application instance*, one can think of superkeys (including all entire rows) and/or values (of one-column superkeys) "as" instances. (Though that very fact shows ER is *dis*oriented.) – philipxy Oct 09 '15 at 10:44
  • @philipxy Thanks for making me think again. I had candidate keys in mind but can't argue against superkeys. At least we can agree that ER is disoriented. – reaanb Oct 09 '15 at 12:19
  • @reaanb I take your advice, because I was talking about rdbms implementation I change it to `table` to avoid confusion with ER term. – Juan Carlos Oropeza Oct 09 '15 at 14:41
  • @reaanb & @ JuanCarlosOropeza PS And for "class/set" I should have written "type/class or set/extent". Plus "class" gets (confusingly) used for both class-as-type and class('s) extent. Also relationship/association instances get called associative entities. (More ER needless coming and going of entities.) (See [this answer](http://stackoverflow.com/a/32862915/3404097).) – philipxy Oct 09 '15 at 20:48
1

Sorry, is this meant to be a real-world database relationship? In all of the many databases I have ever built with customer data, there has always been real cases of either customers with multiple addresses, or more than one organisation at the same address.

I wouldn't want to lead you into a database modelling fallacy by suggesting anything different.

Keith MacDonald
  • 218
  • 2
  • 7
1

It's possible in principle to implement a true 1-1 data structure in some DBMSs. It's very difficult to add data or modify data in such a structure using standard SQL however. Standard SQL only permits one table to be updated at a time and therefore as soon as you insert a row into one or other table the intended constraint is broken.

Here are two examples. First using Tutorial D. Note that the comma between the two INSERT statements ensures that the 1-1 constraint is never broken:

VAR CUSTOMER REAL RELATION {
    id INTEGER} KEY{id};

VAR ADDRESS REAL RELATION {
    id INTEGER} KEY{id};

CONSTRAINT one_to_one (CUSTOMER{id} = ADDRESS{id});

INSERT CUSTOMER RELATION {
    TUPLE {id 1234}
    },
INSERT ADDRESS RELATION {
    TUPLE {id 1234}
    };

Now the same thing in SQL.

CREATE TABLE CUSTOMER (
    id INTEGER NOT NULL PRIMARY KEY);

CREATE TABLE ADDRESS (
    id INTEGER NOT NULL PRIMARY KEY);

INSERT INTO CUSTOMER (id)
    VALUES (1234);

INSERT INTO ADDRESS (id)
    VALUES (1234);

ALTER TABLE CUSTOMER ADD CONSTRAINT one_to_one_1
    FOREIGN KEY (id) REFERENCES ADDRESS (id);

ALTER TABLE ADDRESS ADD CONSTRAINT one_to_one_2
    FOREIGN KEY (id) REFERENCES CUSTOMER (id);

The SQL version uses two foreign key constraints, which is the only kind of multi-table constraint supported by most SQL DBMSs. It requires two INSERT statements which means I could only insert a row before adding the constraints, not after.

A strict one-to-one constraint probably isn't very useful in practice but it's actually just a special case of something more important and interesting: join dependency. A join dependency is effectively an "at least one" constraint between tables rather than "exactly one". In the world outside databases it is common to encounter examples of business rules that ought to be implemented as join dependencies ("each customer must have AT LEAST ONE addresss", "each order must have AT LEAST ONE item in it"). In SQL DBMSs it's hard or impossible to implement join dependencies. The usual solution is simply to ignore such business rules thus weakening the data integrity value of the database.

nvogel
  • 24,981
  • 1
  • 44
  • 82
  • *...some DBMS.* Would you please name a few if you know any. Thanks for your collaboration. – Hans Oct 08 '15 at 23:10
  • Presumably you meant to say "equality dependency" (constraint)? (Or maybe "inclusion dependency", but two of the latter have to hold for one of the former to hold). – philipxy Oct 09 '15 at 09:47
  • I did mean an equality dependency but I always think of an equality dependency as just a special case of a join dependency, i.e. a trivial JD where R{A} JOIN S{A} = R{A} = S{A}. Join dependency is a concept that many people are familiar with. I think fewer people would immediately understand what equality dependency means. – nvogel Oct 09 '15 at 19:53
  • If you sit down and try to explain what you mean, ie how an EQD is just a special case of JD, which it is not, then you will find that the only similarity is that if we assume that the two column( set)s are equal (which is essentially your 'special case') then there are a few similarities between the equations for an EQD & JD but that's it. Which besides being both unhelpful and misleading as an explanation only makes any sense if we *start* with what is an EQD, whence we could just *stop*. Basically, you just have the *impression* that an EQD is or is like a JD, put it doesn't pan out. – philipxy Oct 13 '15 at 04:57
1

Yes, the "shared PK" idiom you show is for 1-to-0-or-1.

The straightforward way to have a true 1-to-1 correspondence is to have one table with Customer and Address as CKs (candidate keys). (Via UNIQUE NOT NULL and/or PRIMARY KEY.) You could offer the separate tables as views. Unfortunately typical DBMSs have restrictions on what you can do via the views, in particular re updating.

The relational way to have separate CUSTOMER and ADDRESS tables and a third table/association/relationship with Customer and Address columns as CKs plus FKs on Customer to and from CUSTOMER and on Address to and from ADDRESS (or equivalent constraint(s)). Unfortunately most DBMSs needlessly won't let you declare cycles in FKs and you cannot impose the constraints without triggers/complexity. (Ultimately, if you want to have proper integrity in a typical SQL database you need to use triggers and complex idioms.)

Entity-oriented design methods unfortunately artificially distinguish between entities, associations and properties. Here is an example where if you consider the simplest design to simply be the one table with PKs then you don't want to always have to have distinct tables for each entity. Or if you consider the simplest design to be the three tables (or even two) with the PKs and FKs (or some other constraint(s) for 1-to-1) then unfortunately typical DBMSs just don't declaratively/ergonomically support that particular design situation.

(Straightforward relational design is to have values (that are sometimes used as ids) 1-to-1 with application things but then just have whatever relevant application relationships/associations/relations and corresponding/representing tables/relations as needed to describe your application situations.)

philipxy
  • 14,867
  • 6
  • 39
  • 83
1

Yes, what you say is true, the dependent side of a 1:1 relationship may not exist -- if only for the time it takes to create the dependent entity after creating the independent entity. In fact, all relationships may have a zero on one side or the other. You can even turn the relationship into a 1:m by placing the FK of the address in the Customer row and making the field not null. You can still have addresses that aren't referenced by any customer.

At first glance, a m:n may look like an exception. The intersection entry is generally defined so that neither FK can be null. But there can be customers and addresses both that have no entry referring to them. So this is really a 0..m:0..n relationship.

What of it? Everyone I've ever worked with has understood that "one" (as in 1:1) or "many" (as in 1:m or m:n) means "no more than this." There is no "exactly this, no more or less." For example, we can design a 1:3 relationship on paper. We cannot strictly enforce it in any database. We have to use triggers, stored procedures and/or scheduled tasks to seek out and call our attention to deviations. Execute a stored procedure weekly, for instance, that will seek and and flag or delete any such orphaned addresses.

Think of it like a "frictionless surface." It exists only on paper.

TommCatt
  • 5,498
  • 1
  • 13
  • 20
1

I see this question as a conceptual misunderstanding. Relations are between different things. Things with a "true 1-to-1 relation" are by definition aspects or attributes of the same thing, and belong in the same table. No, of course a person and and address are not the same, but if they are inseparable, and must always be inserted, deleted, or otherwise acted upon as a unit, then as data they are "the same thing". This is exactly what is described here.

  • Agreed. And if you need to get only the personal data, or the adress data, that is what select statements are for. – jumps4fun Sep 12 '19 at 13:15
0

Yes, and it's actually quite easy: just put both entities in the same table!

OTOH, if you need to keep them in separate tables for some reason, then you need a key in one table referencing1 a key in another, and vice-versa. This, of course, represents a "chicken and egg" problem2 which can be resolved by deferring the enforcement of FKs to the end of the transaction3. This works only on DBMSes that support deferred constraints (such as Oracle and PostgreSQL).


1 Via a foreign key.

2 Inserting a row in the first table is impossible because that would violate the referential integrity towards the second table, but inserting a row in the second table is impossible because that would violate the referential integrity towards the first table, etc... Ditto for deletion.

3 So you simply insert both rows, and then check both FKs.

Community
  • 1
  • 1
Branko Dimitrijevic
  • 50,809
  • 10
  • 93
  • 167
  • "Inserting a row in the first table is impossible" It is impossible *in SQL* only because SQL doesn't support multiple assignment. It is not impossible as a matter of principle. – nvogel Oct 10 '15 at 21:50