2012-04-04 36 views
0

我有一個SQL Server表:如何設計數據庫表來執行非重複的唯一鍵記錄

+----+-------------+-------------------+ 
| ID | CompanyID | CompanyCode  | 
+----+-------------+-------------------+ 
| 1 | 1   | AAAA-123   | 
| 2 | 2   | BBBB-111   | 
| 3 | 1   | AAAA-123   | 
| 4 | 3   | CCCC-999   | 
| 5 | 3   | CCCC-999   | 
| 6 | 1   | AAAA-123   | 
+----+-------------+-------------------+ 

ID場的PK。

CompanyIDCompanyCode字段指定一個唯一的公司,其中一個CompanyID將始終具有相同的CompanyCode(反之亦然),並沒有兩個公司都不會有相同的CompanyID和/或CompanyCode

我想在桌上創建一個規則,如果/當CompanyCodeCompanyID匹配的現有CompanyCode不匹配時,永不允許將記錄添加到表中。

下面是什麼,我不能讓餐桌上出現一個例子:

+----+-------------+-------------------+ 
| ID | CompanyID | CompanyCode  | 
+----+-------------+-------------------+ 
| 1 | 1   | AAAA-123   | 
| 2 | 1   | BBBB-111   |<<<< This record should not be allowed 
| 3 | 1   | AAAA-123   | 
| 4 | 3   | CCCC-999   | 
| 5 | 3   | CCCC-999   | 
| 6 | 1   | AAAA-123   | 
+----+-------------+-------------------+ 

通知與ID=2備案,CompanyCode BBBB-111不匹配了CompanyCode of AAAA-123現有記錄。

我希望這個規則以某種方式存在於表上 - 即我不希望這個規則是查詢和/或存儲過程必須管理的業務規則。

我想你可以說,我想執行重複記錄(上CompanyIDCompanyCode)當且僅當現有CompanyID和/或CompanyCode存在於表。

這是可能做到在表設計水平?或者我堅持不得不在我的腳本中進行管理?

更新

雖然這是不是真的有關我的OP,從我收到的反饋,我想我應該給的CompanyID /企業編碼表的設計有點背景。

首先,這只是一個模擬表設計,試圖解釋我的問題 - 我的真正表與公司無關。

其次,我真正的表是兩個web服務之間的中間人,其中服務1創建一個DeviceID和服務2 收集一個SerialNumber存在於微器件。另外,我真正的表格還包含了這個中間人服務器必須處理的許多其他列。

這個中間人服務的一個奇怪的事情是,我說的表必須允許NULLS DeviceID和SerialNumber - 這一切都取決於哪個服務先發送記錄....我說的太多了,而且還沒有解決我原來的問題,但我認爲我必須澄清我的表格示例,因爲我正在爲突破的標準化問題爭論不休。

+3

爲什麼公司代碼在這裏,而不是在公司的表? – 2012-04-04 12:45:59

+4

這就像您在學習規範化時顯示的早期示例之一 - 如果CompanyCode依賴於CompanyID(反之亦然,在這種情況下),應該有一個表格代表該事實一次,然後只有其中一個鍵應該出現在上表中。 – 2012-04-04 12:56:59

回答

0

好吧,這不是最漂亮的代碼,但它確實強制約束,我想。關鍵是要建立與它定義了兩個唯一索引的索引視圖:

create table dbo.ABC (
    Col1 int not null, 
    Col2 int not null 
) 
go 
create view dbo.ABC_Col1_Col2_dep 
with schemabinding 
as 
    select Col1,Col2,COUNT_BIG(*) as Cnt 
    from 
     dbo.ABC 
    group by 
     Col1,Col2 
go 
create unique clustered index IX_Col1_UniqueCol2 on dbo.ABC_Col1_Col2_dep (Col1) 
go 
create unique nonclustered index IX_Col2_UniqueCol1 on dbo.ABC_Col1_Col2_dep (Col2) 
go 

現在我們插入一些初始數據:

insert into dbo.ABC (Col1,Col2) 
select 1,3 union all 
select 2,19 union all 
select 3,12 

我們可以用完全相同的值添加其他行的Col1Col2

insert into dbo.ABC (Col1,Col2) 
select 1,3 

但是,如果我們選擇一個值Col2已用於其他Col1或副反之亦然,我們得到的錯誤:

insert into dbo.ABC (Col1,Col2) 
select 2,3 
go 
insert into dbo.ABC (Col1,Col2) 
select 1,5 

這裏的技巧是觀察這個查詢:

select Col1,Col2,COUNT_BIG(*) as Cnt 
    from 
     dbo.ABC 
    group by 
     Col1,Col2 

只會有一行特定Col1值,只有一排用特別是Col2的值,前提是您要強制執行的約束沒有被破壞 - 但是一旦將不匹配的行插入基表中,此查詢將返回多行。

4
CREATE UNIQUE INDEX idx_name ON TableName(CompanyID, CompanyCode) 

(假設您的表名爲TableName)。

但是,您應該知道,此設計違反了數據庫規範化原則。正確規範化的數據庫將有一個單獨的表格,只有CompanyID和CompanyName字段。然後,您可以修改示例中的表格以僅具有CompanyID字段;公司代碼將在需要時「查找」(使用VIEW)。

這種設計具有以下優點:

  1. 變得根本不可能有不同的名稱相同的公司ID。

  2. 在公司更改其代碼的情況下,您只需更新單個表中的一條記錄,該記錄防錯並且更快。

  3. 您節省了存儲空間。

它有一個小缺點,就是你必須加入公司表來獲取代碼。在關係數據庫中,這不一定是一個真正的缺點(加入標準化數據是關係數據庫,),但通過消除CompanyID並將代碼用作公司的主鍵,您甚至可以消除這種情況。如果代碼是不可變的,我只會考慮這一點(對於給定的公司,它不會隨時間而改變)。

+0

這將不起作用,因爲唯一索引不會允許多個記錄包含相同的CompanyID和CompanyCode。注意我的OP中的示例表如何包含多個具有重複ID /代碼的記錄。 – Jed 2012-04-04 13:26:42

2

我建議你不要在表格中存儲CompanyID和CompanyCode。相反,你應該有另一個表,每個CompanyId存儲1行,也有相應的代碼。然後,您可以設置一個外鍵以確保此表中的CompanyId存在於另一個表中。

2

我不知道如何制定規則來強制執行此操作,但是您對同一事物使用了兩個獨立的外鍵(這將永遠匹配)......沒有公司代碼會更好一些在這個表中,當你需要這些數據,或者以其他方式重新設計它時,將它加入到不同的表中。

0

您正在違反第3範式。非密鑰依賴於另一個非密鑰。 CompanyCode依賴於CompanyID。其他人所說的補救措施是創建一個CompanyID,CompanyCode表,其中CompanyID是PK。從您的表中刪除CompanyCode並在ComanyID上創建指向您新表的FK關係。 http://www.phlonx.com/resources/nf3/ http://en.wikipedia.org/wiki/Third_normal_form

相關問題