2014-02-06 25 views
1

我有一個問題,我不知道如何正確解決。我目前的設計由兩個表格組成。員工和employee_management。我的RDBMS是MySQL。關係表設計:防止循環引用

員工:

CREATE TABLE `employee` (
    `id` int(11) NOT NULL AUTO_INCREMENT, 
    `name` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL, 
    PRIMARY KEY (`id`) 
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci 

employee_management:

CREATE TABLE `employee_management` (
    `manager_id` int(11) NOT NULL, 
    `employee_id` int(11) NOT NULL, 
    UNIQUE INDEX `association` (`manager_id`,`employee_id`), 
    FOREIGN KEY (`manager_id`) 
    REFERENCES employee(id) 
    ON UPDATE CASCADE ON DELETE RESTRICT, 
    FOREIGN KEY (`employee_id`) 
    REFERENCES employee(id) 
    ON UPDATE CASCADE ON DELETE RESTRICT 
) 

測試數據:

INSERT INTO employee(name) VALUES(
    'Bob Smith' 
) 
INSERT INTO employee(name) VALUES(
    'Bill Smith' 
) 

INSERT INTO employee_management(manager_id, employee_id) VALUES(
    1,2 
) 
INSERT INTO employee_management(manager_id, employee_id) VALUES(
    2,1 
) 

選擇從employee_management行顯示了這個:

+------------+-------------+ 
| manager_id | employee_id | 
+------------+-------------+ 
|   2 |   1 | 
|   1 |   2 | 
+------------+-------------+ 

返回的行表明Bill Smith管理Bob Smith,Bob Smith管理Bill Smith,我認爲這是一個循環引用。兩個人互相管理沒有意義。我認爲UNIQUE INDEX會阻止插入具有任何現有值組合的行,但這不起作用。我知道我可以防止這種情況發生在應用程序級別,但我不確定這是否是適當的事情,但這是必須在應用程序級別執行的事情,還是我可以做的事情防止循環引用?管理者不應該也有管理者。

+0

鮑勃史密斯可以管理管理鮑勃史密斯的比爾史密斯的迪克瓊斯嗎? – Strawberry

+1

經理沒有經理。 –

+0

在這種情況下,請考慮切換到嵌套集模型 - 或者像您說的那樣,在應用程序級別管理業務邏輯 – Strawberry

回答

1

造成這種複雜性的主要原因是對DBMS的 聲明這些約束的支持不足。

可以說明只有兩種類型的裝飾性表約束:

  • 唯一識別的屬性(鍵)
  • 子集要求引用回到相同的表,在這種情況下 一個子集的要求是表約束(外關鍵到相同的 表)。

實現所有其他類型的表約束要求您開發過程性數據完整性代碼 。在實踐中,這意味着您經常不得不採用觸發的程序策略或應用程序業務層的實現。

thisthis post,您可以使用觸發器來檢查,如果下面的查詢結果大於0,則回滾變化

SELECT count(*) FROM employee_management e1 
      WHERE EXISTS (SELECT * FROM employee_management e2 
      WHERE 
      e1.manager_id = e2.employee_id 
      AND 
      e1.employee_id = e2.manager_id) 

作爲一個註腳你可能有一個外鍵從員工到員工顯示僱員的經理。

+0

「不好的支持」特定於MySQL。在許多其他數據庫管理系統中(例如Postgres),你可以很容易地定義一個索引來防止'(1,2)'和'(2,1)' –

+0

我也無法在Oracle中找到索引解決方案! –

+1

請看這裏:http://sqlfiddle.com/#!4/e5ac7/1 –

0

我需要一個觸發器在SQL Server中完成這項工作 - 如果它可以幫助某人解決同樣的問題,這裏是觸發器定義。

CREATE TRIGGER iu_erp_user 
ON [dbo].[erp_user] 
FOR INSERT, UPDATE 
AS 
BEGIN 
SET NOCOUNT ON 

declare @erp_user_id int 
declare @supervisor_supervisor_id int 

select @erp_user_id = i.erp_user_id, @supervisor_supervisor_id = eu.supervisor_id 
from inserted i 
left join erp_user eu on i.supervisor_id = eu.erp_user_id 

if @erp_user_id = @supervisor_supervisor_id 
begin 
    RAISERROR('Circular reference created.', 16, 1) 
    ROLLBACK TRAN 
end 

END 
GO