25

I'm defining a database for a customer/ order system where there are two highly distinct types of customers. Because they are so different having a single customer table would be very ugly (it'd be full of null columns as they are pointless for one type).

Their orders though are in the same format. Is it possible to have a CustomerId column in my Order table which has a foreign key to both the Customer Types? I have set it up in SQL server and it's given me no problems creating the relationships, but I'm yet to try inserting any data.

Also, I'm planning on using nHibernate as the ORM, could there be any problems introduced by doing the relationships like this?

Aaron Powell
  • 24,927
  • 18
  • 98
  • 150
  • What do you expect the FKs to *do*? You aren't clear about any restrictions on the CustomerId columns are in your tables. So it's not clear what constraints would be appropriate to declare. – philipxy Dec 16 '19 at 04:43

8 Answers8

26

No, you can't have a single field as a foreign key to two different tables. How would you tell where to look for the key?

You would at least need a field that tells what kind of user it is, or two separate foreign keys.

You could also put the information that is common for all users in one table and have separate tables for the information that is specific for the user types, so that you have a single table with user id as primary key.

Guffa
  • 687,336
  • 108
  • 737
  • 1,005
  • 2
    Agreed. Normalisation is the key here. – jva Jul 27 '09 at 08:07
  • 1
    @Guffa: -1 because "No, you can't have a single field as a foreign key to two different tables" - this statement is incorrect (at least on sql server 2005). Give it a whirl. – Liao Jul 27 '09 at 09:08
  • 2
    @Liao: I don't think that you understand the situation... If you for example has the foreign key value 42, how would you know if it's the key in table A or table B? – Guffa Jul 27 '09 at 16:57
  • I understand the normalization/bridge aspect of achieving the result, but to answer the question... if it were allowed, it would be the key in table A and table B. That would be the point. I have trouble seeing why anyone would do that, but I also don't see why it's not possible if you wanted to, for example (bad design) make a User table and a UserMetadata table both using UserID as the key. Really UserID should be FK to User, or MetadataID in user table. But... as far as technical reasons, SQL should support bad design decisions... at least that's my opinion. I'd rather not be restricted. – Robert Noack Jun 27 '14 at 18:41
  • The FK would also force the creation of MetaData. For example a user could be registered and enter their MetaData later. The "double FK" could be a weird DB trick to say "Don't let an entry be put into this table until the metadata is made" because the 2nd FK would not be able to be met if the field is not-null ? – Robert Noack Jun 27 '14 at 18:44
  • I just asked a question where the only good design solution that I see is to use a foreign key to two tables. Maybe that example can be of some help in this discussion: http://stackoverflow.com/questions/29659540/enforcing-common-foreign-key-in-many-to-many-relationship/29659817#29659817 – Jadiel de Armas Apr 15 '15 at 20:56
  • @JadieldeArmas: That's a foreign key to two records in two tables, not a foreign key to a record in one table or the other, so that's perfectly doable. – Guffa Apr 15 '15 at 22:04
  • Why the downvote? If you don't explain what it is that you think is wrong, it can't improve the answer. – Guffa Apr 15 '15 at 23:35
  • This is wrong. A FK is a list of columns whose subrows appear elsewhere as PK/UNIQUE. If that's true multiple times, that's multiple FKs. If you are trying to say that having multiple FKs from one list doesn't say that the subrows must merely appear in one or some of the referenced places, that's true, but you haven't actually said that--you just wrongly say certain FKs can't be declared--you don't clearly describe the effect--& the question doesn't ask that--it's not clear about what constraints hold in its design. – philipxy Dec 16 '19 at 04:44
4

A foreign key can only reference a single primary key, so no. However, you could use a bridge table:

CustomerA <---- CustomerA_Orders ----> Order
CustomerB <---- CustomerB_Orders ----> Order

So Order doesn't even have a foreign key; whether this is desirable, though...

Marc Gravell
  • 1,026,079
  • 266
  • 2,566
  • 2,900
3

I inherited a SQL Server database where this was done (a single column used in four foreign key relationships with four unrelated tables), so yes, it's possible. My predecessor is gone, though, so I can't ask why he thought it was a good idea.

He used a GUID column ("uniqueidentifier" type) to avoid the ambiguity problem, and he turned off constraint checking on the foreign keys, since it's guaranteed that only one will match. But I can think of lots of reasons that you shouldn't, and I haven't thought of any reasons you should.

Yours does sound like the classical "specialization" problem, typically solved by creating a parent table with the shared customer data, then two child tables that contain the data unique to each class of customer. Your foreign key would then be against the parent customer table, and your determination of which type of customer would be based on which child table had a matching entry.

Dave G.
  • 31
  • 1
1

You can create a foreign key referencing multiple tables. This feature is to allow vertical partioining of your table and still maintain referential integrity. In your case however, this is not applicable.

Your best bet would be to have a CustomerType table with possible columns - CustomerTypeID, CustomerID, where CustomerID is the PK and then refernce your OrderID table to CustomerID.

Raj

Raj
  • 10,653
  • 2
  • 45
  • 52
1

I know this is a very old question; however if other people are finding this question through the googles, and you don't mind adding some columns to your table, a technique I've used (using the original question as a hypothetical problem to solve) is:

  1. Add a [CustomerType] column. The purpose of storing a value here is to indicate which table holds the PK for your (assumed) [CustomerId] FK column. Optional - addition of a check constraint (to ensure CustomerType is in CustomerA or CustomerB) will help you sleep better at night.

  2. Add a computed column for each [CustomerType], eg:
    [CustomerTypeAId] as case when [CustomerType] = 'CustomerA' then [CustomerId] end persisted
    [CustomerTypeBId] as case when [CustomerType] = 'CustomerB' then [CustomerId] end persisted

  3. Add your foreign keys to the calculated (and persisted) columns.

Caveat: I'm primarily in a MSSQL environment; so I don't know how well this translates to other DBMS (ie: Postgres, ORACLE, etc).

Paul
  • 1,502
  • 11
  • 19
  • 1
    I would be grateful if you could provide us with an implementation related to your answer. I'm using java + jpa +db2 database. – user3072470 Nov 03 '22 at 14:27
0

Two distinct types of customer is a classic case of types and subtypes or, if you prefer, classes and subclasses. Here is an answer from another question.

Essentially, the class-table-inheritance technique is like Arnand's answer. The use of the shared-primary-key technique is what allows you to get around the problems created by two types of foreign key in one column. The foreign key will be customer-id. That will identify one row in the customer table, and also one row in the appropriate kind of customer type table, as the case may be.

Community
  • 1
  • 1
Walter Mitty
  • 18,205
  • 2
  • 28
  • 58
0

As noted, if the key is, say, 12345, how would you know which table to look it up in? You could, I suppose, do something to insure that the key values for the two tables never overlapped, but this is too ugly and painful to contemplate. You could have a second field that says which customer type it is. But if you're going to have two fields, why not have one field for customer type 1 id and another for customer type 2 id.

Without knowing more about your app, my first thought is that you really should have a general customer table with the data that is common to both, and then have two additional tables with the data specific to each customer type. I would think that there must be a lot of data common to the two -- basic stuff like name and address and customer number at the least -- and repeating columns across tables sucks big time. The additional tables could then refer back to the base table. As there is then a single key for the base table, the issue of foreign keys having to know which table to refer to evaporates.

Jay
  • 26,876
  • 10
  • 61
  • 112
-1
  1. Create a "customer" table include all the columns that have same data for both types of customer.
  2. Than create table "customer_a" and "customer_b"
  3. Use "customer_id" from "consumer" table as foreign key in "customer_a" and "customer_b"

                    customer
                        |
         ---------------------------------
         |                               |
    cusomter_a                      customer_b
    
Anand
  • 610
  • 6
  • 13