Skip to content
Advertisement

SQL One-to-One Relationship Definition

I’m designing a database and I’m not sure how to define one of the relationships. Here’s the situation:

  1. An invoice is created
  2. If the product is not in stock then it needs to be manufactured and so a work order is created.

The relationship is one-to-one. However work orders are sometimes created for other purposes so the WorkOrder table will also be linked to other tables in a similar one-to-one relationship. Also, some Invoices won’t have a work order at all. This means I can’t define these relationships in the normal way by using the same primary key in both tables. Instead of doing this I’ve created a linking table and then set unique indexes on both fields to define the one-to-one relationship (see image).

DB Diagram
(source: markevans.org)
.

Is this the best way?

Cheers
Mark

EDIT: I just realised that this design will allow a single work order to be linked to an invoice and also to one of the other tables I mentioned via 2 linking tables. I guess no solution is perfect.

Advertisement

Answer

Okay, this answer is SQL Server specific, but should be adaptable to other RDBMSs, with a little work. So far as I see, we have the following constraints:

  • An invoice may be associated with 0 or 1 Work Orders
  • A Work Order must be associated with an invoice or an ABC or a DEF

I’d design the WorkOrder table as follows:

So, basically, this table is constrained to only FK to one other table, no matter how many PKs are defined. If necessary, a computed column could tell you the “Type” of item that this is linked to, based on which FK column is non-null, or the type and a single int column could be real columns, and InvoiceID, ABCID, etc could be computed columns.

The final thing to ensure is that an invoice only has 0 or 1 Work Orders. If your RDMBS ignores nulls in unique constraints, this is as simple as applying such a constraint to each FK column. For SQL Server, you need to use a filtered index (>=2008) or an indexed view (<=2005). I’ll just show the filtered index:


Another way to deal with keeping WorkOrders straight is to include a WorkOrder type column in WorkOrder (e.g. ‘Invoice’,’ABC’,’DEF’), including a computed or column constrained by check constraint to contain the matching value in the link table, and introduce a second foreign key:

The only disadvantage to this model, although closer to your original proposal, is that you can have a work order that isn’t actually linked to any other item (although it claims to be for an e.g INVOICE).

User contributions licensed under: CC BY-SA
2 People found this is helpful
Advertisement