Sql Server - Foreign key referencing multiple columns one of which isn't in the source table
I've got a problem with foreign key. This is my DB structure (simplified):
Table 'Languages'
LanguageID - primary key
LanguageName - string (for example 'English')
..
Table 'Users'
UserID - primary key
LanguageID - byte (FK to Languages.LanguageID)
..
Table 'Localization'
LocalizationID - / compound primary key
LanguageID - \ compound primary key (FK t开发者_运维知识库o Languages.LanguageID)
Data - string (for example 'My Program' in English)
Table 'UserLocalization'
UserLocalizationID - primary key
UserID - which user (FK to Users.UserID)
..
some other useful columns -> this table cannot be removed **EDITED**
..
LocalizationID - what string (FK to Localization.?) <- oops, not really because
LanguageID is needed
for FK to 'Localization'
How to make a FK (or any other integrity check) in 'UserLocalization' to 'Localization'. Is it possible in this configuration ? Or is it not ok, and therefore some restructuralization (really ?) is needed ? If so how to accomplish it ?
Edit: A bit cleaned up for better clarity.
The simple answer is: if you have your table Localization
like this:
LocalizationID - / compound primary key
LanguageID - \ compound primary key (FK to Languages.LanguageID)
Data - string (for example 'My Program' in English)
and you want to add a foreign key to another table referencing this table, that foreign key needs to have both columns of your PK here at hand, so it could be:
Table 'UserLocalization'
UserLocalizationID - primary key
UserID - which user (FK to Users.UserID)
(LocalizationID, LanguageID) - FK to Localization
That's one of the downsides of compound primary keys - any FK referencing them must also include all columns of the compound PK - no exceptions / tricks / workarounds possible. With two columns, that's still doable, but with four, five, ten columns it gets really really messy. It also means any JOIN
to that table must contain all common fields - and again, with two it's still ok, but with more, it gets really messy.
This is one of the reasons I would often consider adding an artificial surrogate key to tables where I only have a compound PK - just to simplify FK joins to it.
Get rid of the UserLocalization
table. Use this SQL instead to find the localized strings for the users:
SELECT * FROM Users INNER JOIN Localization ON Users.LanguageID = Localization.LanguageID
All users with the same language need/have the same localization records, so you don't need to add any more integrity checks; you're doing all the checks already with the FKs on LanguageID
in the Users
and Localization
tables.
If you want to find a specific user's localized data/strings just put a WHERE UserID = [Whatever]
on the end of the SQL.
精彩评论