I have a Post entity and a FbPost entity.
Post.FbPost is either null or a FbPost, and no two Post en
Superclass It!
I think the best solution is to make the Post table a superclass of the FBPost table. (Note: I'm going to use PostID and FBPostID here to make it absolutely clear what I'm referring to.) That is, remove the FBPostID column from your Post table entirely, after updating the FBPost.FBPostID column to match the corresponding PostID. Instead of each FBPostID having its own unique value, it will share the same value as the PostID. In my professional opinion, this is the right way to model a one-to-zero-or-one relationship. It has a huge advantage of being foolproof, and not requiring any additional indexes, triggers, or constraints beyond what a simple FK already provides.
Note: I'm assuming that we can just update the FBPostID column in FBPost once we drop the (presumed) PK on it. If it is an identity column, then more work will be required--just to add a new column that will become the new PK, and to rename the original column. If column order matters, the data will have to be moved to a new table in order to make a new column appear in the desired location.
Be sure to think about concurrency while working on this so no data can be improperly read or modified while the change is taking place or before the altered data handling is updated.
Why you would choose this
When you're modeling an is-a relationship instead of a has-a relationship, and the two entities participate as zero-to-zero-or-one, then they should share the same surrogate key, because really they're the same entity (you're actually modeling an is-sometimes-a relationship).
Even though changing to this database model will take a bit of work, it's totally worth it to repair a suboptimal design. Your relational database's design should always leverage the core relational functionality available. Why would you do anything else:
CREATE TABLE command.Similarly, you would use a foreign key/primary key combination to model an is-sometimes-a relationship, without having to do weird NULL-allowing unique constraints or filtered indexes to accomplish that purpose.
Example Change Script
It's not even too bad! Here is some script that should get you pretty well started:
BEGIN TRAN;
ALTER TABLE dbo.Post DROP CONSTRAINT FK_Post_FBPostID; -- referencing FBPost
-- Also remove all FKs from any other tables referencing FBPostID
ALTER TABLE dbo.FBPost DROP CONSTRAINT PK_FBPost; -- FBPostID column not PK
ALTER TABLE dbo.FBPost ADD OriginalFBPostID int;
UPDATE dbo.FBPost WITH (HOLDLOCK, UPDLOCK) SET OriginalFBPostID = FBPostID;
UPDATE F
SET F.FBPostID = P.PostID
FROM
dbo.FBPost F
INNER JOIN dbo.Post P
ON F.OriginalFBPostID = P.FBPostID;
-- Perform a similar update on all other tables referencing FBPostID
-- Now, the two most important changes
ALTER TABLE dbo.FBPost ADD CONSTRAINT PK_FBPost PRIMARY KEY CLUSTERED (FBPostID);
ALTER TABLE dbo.FBPost ADD CONSTRAINT FK_FBPost_PostID FOREIGN KEY
REFERENCES dbo.Post (PostID); -- This is where the magic happens!
ALTER TABLE dbo.SomeTable ADD CONSTRAINT FK_SomeTable_FBPostID FOREIGN KEY
REFERENCES dbo.FBPost (FBPostID); -- and all other tables referencing FBPostID
EXEC sp_rename 'dbo.Post.FBPostID', 'OriginalFBPostID'; -- should stop using it
ALTER TABLE dbo.Post DROP COLUMN FBPostID; -- Or even better, remove it.
COMMIT TRAN;
ALTER TABLE dbo.FBPost DROP COLUMN OriginalFBPostID; -- Meaningless now
-- If you keep OriginalFBPostID and it is identity, please copy the values
-- to a new non-identity column and drop it so you don't keep generating more
Finally, modify your Post/FBPost insertion code to use the PostID as the FBPostID.
New Query Appearance
Just to drive home the point, your joins between the tables used to look like this:
SELECT
P.Something,
F.SomethingElse
FROM
dbo.Post P
INNER JOIN dbo.FBPost F
ON P.FBPostID = F.FBPostID
But now they will look like this:
SELECT
P.Something,
F.SomethingElse
FROM
dbo.Post P
INNER JOIN dbo.FBPost F
ON P.PostID = F.FBPostID -- the important part
The problem is completely solved now! Your tables even take up less space (losing the FBPostID column from Post). You don't have to monkey around with an FK that allows multiple NULLs. With a PK on FBPostID in the FBPost table it is obvious that you can only have one FBPost row per FBPostID.