2012-04-24 121 views
27

我想在SQL Server 2008 R2中創建一對一的關係。如何在SQL Server中創建真正的一對一關係

我有兩個表tableAtableB,我設置tableB的主鍵作爲外鍵,它參考tableA的主鍵。但是當我使用實體框架數據庫時,模型是1到0..1。

任何人都知道如何在數據庫中創建真正的1對1關係?

在此先感謝!

回答

37

我敢肯定,在SQL Server中技術上不可能有一個真正的1對1關係,因爲這意味着你將有同時插入兩個記錄(否則你會得到一個約束插入時出錯),在兩個表中,兩個表彼此具有外鍵關係。

這就是說,用外鍵描述的數據庫設計是1到0..1的關係。沒有限制可能需要tableB中的記錄。您可以與在tableB中創建記錄的觸發器建立僞關係。

所以有一些僞解決方案

首先,存儲在一個單一的表中的數據。那麼你在EF中就沒有問題了。或者其次,你的實體必須足夠聰明,除非它有相關的記錄,否則不允許插入。

第三,也很可能是you have a problem you are trying to solve, and you are asking us why your solution doesn't work instead of the actual problem you are trying to solve (an XY Problem)

UPDATE

現實解釋如何1比1的關係不工作,我將使用Chicken or the egg dilemma的比喻。我不打算解決這個難題,但如果你有一個約束來說明爲了給雞蛋桌添加雞蛋,雞的關係必須存在,雞必須存在於桌子上,然後你不能將雞蛋添加到蛋表中。相反的情況也是如此。如果沒有與雞蛋表中存在的雞蛋和雞蛋的關係,就不能添加雞肉。因此,在不破壞任何規則/約束條件的情況下,不會在數據庫中製作任何記錄。

數據庫命名爲的一對一關係有誤導性。我所見過的所有關係(在我的經歷之前)將作爲一對一(零關係或一對)關係更具描述性。

+0

「......這意味着你將不得不同時插入兩個記錄」,所以一對多關係意味着你需要同時插入所有記錄? – 2012-04-24 06:28:52

+0

不,因爲一對多實際上是1到0 ..(x)。仍然沒有要求在許多關係中有任何記錄。 :D(這是關於EF如何描述關係的具體說明,而不是我) – 2012-04-24 06:30:22

+0

據我記得,從我的大學時代(很久很久以前),在關係數據庫中存在着一對一的關係理論。儘管如此,我仍然可能是錯的,並且在sql-server中仍然沒有明確的一對一關係。對不起,什麼是EF? – 2012-04-24 06:55:09

46

將外鍵設置爲主鍵,然後在兩個主鍵字段上設置關係。而已!你應該在關係線的兩端看到一個關鍵標誌。這代表一對一。

enter image description here

檢查:SQL Server Database Design with a One To One Relationship

+16

這將在EF中產生1到0..1的關係。 – 2012-04-24 06:05:21

+3

@ErikPhilips我們如何通過不使用圖表編寫查詢來實現這一目標? – jason 2014-06-23 12:04:31

+0

@jason你寫的查詢是什麼意思?你的意思是說,我如何用T-SQL中描述的關係型Pranay創建兩個表? – 2014-07-29 20:13:55

12

這可以通過創建一個簡單的主外鍵關係,並以下列方式中的外鍵列設置爲唯一要做:

CREATE TABLE [Employee] (
    [ID] INT PRIMARY KEY 
, [Name] VARCHAR(50) 
); 

CREATE TABLE [Salary] (
    [EmployeeID] INT UNIQUE NOT NULL 
, [SalaryAmount] INT 
); 

ALTER TABLE [Salary] 
ADD CONSTRAINT FK_Salary_Employee FOREIGN KEY([EmployeeID]) 
    REFERENCES [Employee]([ID]); 

Schema

INSERT INTO [Employee] (
    [ID] 
, [Name] 
) 
VALUES 
    (1, 'Ram') 
, (2, 'Rahim') 
, (3, 'Pankaj') 
, (4, 'Mohan'); 

INSERT INTO [Salary] (
    [EmployeeID] 
, [SalaryAmount] 
) 
VALUES 
    (1, 2000) 
, (2, 3000) 
, (3, 2500) 
, (4, 3000); 
看到

檢查,一切都很好現在

SELECT * FROM [Employee]; 
SELECT * FROM [Salary]; 

一般在主外的關係(一對多), 可以輸入多次EmployeeID, 但這裏的錯誤將被拋出

INSERT INTO [Salary] (
    [EmployeeID] 
, [SalaryAmount] 
) 
VALUES 
    (1, 3000); 

以上聲明將顯示爲錯誤

Violation of UNIQUE KEY constraint 'UQ__Salary__7AD04FF0C044141D'. 
    Cannot insert duplicate key in object 'dbo.Salary'. The duplicate key value is (1). 
+3

這將在實體框架中產生1到0..1的關係。您創建了一個沒有現有工資的員工。 – 2015-11-19 14:28:50

+0

我對這最後一個例子有點好奇。如果只是將Salary對象添加到Employee類中,我將在EF中不做進一步的操作,只需在代碼中說:var salary = Employee(Id).Salary ??? – 2016-01-19 08:46:59

3

有一種方法我知道如何在不使用觸發器,計算列,附加表或其他「異國情調」技巧(僅限外鍵和唯一約束)的情況下實現嚴格的*一對一關係,並提供一個小警告。

我會借鑑已接受答案中的雞和雞蛋概念來幫助我解釋警告。

這是一個事實,無論是雞還是雞蛋都必須先來(無論如何都是現在的數據庫)。幸運的是,這個解決方案並不具有政治性,也沒有規定哪一個必須首先實現 - 它留給實施者。

需要注意的是,允許記錄在技術上「先到達」的表格可以在沒有相應記錄的情況下在另一個表格中創建記錄;然而,在這個解決方案中,只允許一個這樣的記錄。當僅創建一條記錄(只有雞或蛋)時,除非'寂寞'記錄被刪除或在另一個表中創建了匹配記錄,否則不能再向這兩個表中的任何一個添加記錄。

解決方案:

外鍵添加到每個表,引用其他,添加唯一約束到每個外鍵,使一個外鍵可爲空,其他不能爲空,也是一個主鍵。爲此,可空列上的唯一約束必須只允許一個空值(這是SQL Server中的情況,不確定其他數據庫)。

CREATE TABLE dbo.Egg (
    ID int identity(1,1) not null, 
    Chicken int null, 
    CONSTRAINT [PK_Egg] PRIMARY KEY CLUSTERED ([ID] ASC) ON [PRIMARY] 
) ON [PRIMARY] 
GO 
CREATE TABLE dbo.Chicken (
    Egg int not null, 
    CONSTRAINT [PK_Chicken] PRIMARY KEY CLUSTERED ([Egg] ASC) ON [PRIMARY] 
) ON [PRIMARY] 
GO 
ALTER TABLE dbo.Egg WITH NOCHECK ADD CONSTRAINT [FK_Egg_Chicken] FOREIGN KEY([Chicken]) REFERENCES [dbo].[Chicken] ([Egg]) 
GO 
ALTER TABLE dbo.Chicken WITH NOCHECK ADD CONSTRAINT [FK_Chicken_Egg] FOREIGN KEY([Egg]) REFERENCES [dbo].[Egg] ([ID]) 
GO 
ALTER TABLE dbo.Egg WITH NOCHECK ADD CONSTRAINT [UQ_Egg_Chicken] UNIQUE([Chicken]) 
GO 
ALTER TABLE dbo.Chicken WITH NOCHECK ADD CONSTRAINT [UQ_Chicken_Egg] UNIQUE([Egg]) 
GO 

要插入,首先必須插入一個雞蛋(對於雞爲空)。現在,只能插入一隻雞,並且必須參考「無人認領」的雞蛋。最後,添加的蛋可以更新,並且必須參考「無人認領」的雞。在任何時候,兩隻雞都不能參照相同的雞蛋,反之亦然。

要刪除,可以遵循相同的邏輯:將雞蛋的雞更新爲空,刪除新的「無人認領」雞,刪除雞蛋。

此解決方案還允許輕鬆交換。有趣的是,交換可能是使用這種解決方案的最強有力的論據,因爲它具有潛在的實際用途。通常,在大多數情況下,通過簡單地將兩個表重構爲一個,可以更好地實現兩個表的一對一關係;然而,在一個潛在的情況下,這兩個表格可能代表真正獨立的實體,這些實體需要嚴格的一對一關係,但需要經常交換「合作伙伴」或整體重新安排,同時仍保持一對一重新安排後的一對一關係。如果使用更常見的解決方案,則對於所有要重新排列的對,其中一個實體的所有數據列將不得不被更新/重寫,而與此解決方案相反,只需要重新排列一列外鍵(可以爲空的外鍵列)。

那麼,這是我能用標準約束做的最好的事情(不要判斷:)也許有人會覺得它有用。

+1

這將在實體框架中產生1到0..1的關係。 – 2016-10-20 19:22:34

+2

當然,在其他SQL數據庫服務器(如Oracle或PostgreSQL)中,這可以通過正確執行延遲約束來完成,這些約束在提交事務時進行檢查,而不是在插入行時進行,從而避免雞與蛋問題。令人驚訝的是,MS已經忽略了現在已有25年的SQL-92標準的這一部分。 – DaveBoltman 2017-05-08 10:26:18

+2

在MS SQL Server中獲得真正的1:1關係的另一個更長期的方法是投票了這個連接項:https://connect.microsoft.com/SQLServer/feedback/details/124728/option-to-defer- foreign-key-constraint-checking-until-transaction-commit – DaveBoltman 2017-05-08 10:26:42

1

1對1 SQL中的關係通過將兩個表的字段合併爲一個!

我知道你可以用1對1關係在兩個實體中拆分表。大多數情況下,您使用這種方式是因爲您希望在「表格中重要的二進制數據字段」上使用延遲加載。

例如:您有一個包含名稱列(字符串),可能是某個元數據列,縮略圖列和圖片本身varbinary(max)的圖片的表格。在您的應用程序中,您肯定只會在收藏夾控件中首先顯示名稱和縮略圖,然後僅在需要時才加載「全部圖片數據」。

如果這是你在找什麼。這是所謂的「表分裂」或「水平分裂」。

https://visualstudiomagazine.com/articles/2014/09/01/splitting-tables.aspx

+1

這將在實體框架中產生1到0..1的關係。 – 2017-01-20 15:47:46

0

實現這一點的最簡單的方法是僅創建表1與兩個表A和B字段NOT NULL。這樣就不可能有一個沒有另一個。

相關問題