Khóa ngoại đề cập đến khóa chính trên nhiều bảng?


91

Tôi có hai bảng cụ thể là worker_ce và Employ_sn trong cơ sở dữ liệu nhân viên.

Cả hai đều có các cột khóa chính duy nhất tương ứng.

Tôi có một bảng khác được gọi là các khoản khấu trừ, có cột khóa ngoại mà tôi muốn tham chiếu đến các khóa chính của worker_ce cũng như worker_sn. Điều này có khả thi không?

ví dụ

employees_ce
--------------
empid   name
khce1   prince

employees_sn
----------------
empid   name
khsn1   princess

vậy điều này có khả thi không?

deductions
--------------
id      name
khce1   gold
khsn1   silver

Câu trả lời:


98

Giả sử rằng tôi đã hiểu đúng kịch bản của bạn, thì đây là điều tôi sẽ gọi là cách đúng để thực hiện điều này:

Bắt đầu từ mô tả cấp cao hơn về cơ sở dữ liệu của bạn! Bạn có nhân viên và nhân viên có thể là nhân viên "ce" và nhân viên "sn" (bất kể đó là gì). Trong thuật ngữ hướng đối tượng, có một lớp "nhân viên", với hai lớp con được gọi là "nhân viên ce" và "nhân viên sn".

Sau đó bạn dịch này mô tả cao cấp cho ba bảng: employees, employees_ceemployees_sn:

  • employees(id, name)
  • employees_ce(id, ce-specific stuff)
  • employees_sn(id, sn-specific stuff)

Vì tất cả nhân viên đều là nhân viên (duh!), Mọi nhân viên sẽ có một hàng trong employeesbảng. nhân viên "ce" cũng có một hàng trong employees_cebảng, và nhân viên "sn" cũng có một hàng trong employees_snbảng. employees_ce.idlà một chìa khóa ngoại employees.id, giống nhưemployees_sn.id .

Để đề cập đến một nhân viên thuộc bất kỳ loại nào (ce hoặc sn), hãy tham khảo employeesbảng. Đó là, khóa ngoại mà bạn gặp sự cố nên tham khảo bảng đó!


17
Làm thế nào để bạn làm cho ce và sn loại trừ lẫn nhau? Vì một nhân viên không thể đồng thời là ce và sn, nên sẽ là thông lệ tốt để phản ánh điều đó trong cơ sở dữ liệu. Tôi đang gặp vấn đề này ngay bây giờ.
Rolf

Tôi nghĩ rằng nhiều phím cột có thể giúp giải quyết vấn đề trong nhận xét trước đây của tôi ... đang tìm kiếm điều đó ngay bây giờ.
Rolf

12
Bạn có thể buộc nhân viên chỉ có trong một bảng (và một bảng chính xác) bằng cách lưu trữ một kiểu trong bảng cơ sở cũng như các bảng dẫn xuất. Đặt id khóa chính, khóa duy nhất trên (id, type), khóa ngoại của bảng con được bật (id, type) và đặt ràng buộc KIỂM TRA trên mỗi bảng con để chỉ có đúng loại. Hoặc, nếu cơ sở dữ liệu của bạn thực hiện các ràng buộc kiểm tra toàn cục (và không bị phạt tốc độ lớn), tất nhiên bạn có thể chỉ thực hiện kiểm tra KHÔNG TỒN TẠI.
derobert 25/10/11

Kiểm tra Câu trả lời này để biết giải thích đầy đủ và chi tiết triển khai.
PerformanceDBA

Làm thế nào để biết một nhân viên có id cụ thể là 'se' hay 'sn'?
mhrsalehi

22

Bạn có thể thêm hai ràng buộc khóa ngoại (thành thật mà nói: tôi chưa bao giờ thử nó), nhưng sau đó nó sẽ đòi hỏi hàng cha tồn tại trong cả hai bảng.

Thay vào đó, bạn có thể muốn tạo một siêu kiểu cho hai kiểu phụ nhân viên của mình và sau đó trỏ khóa ngoại vào đó. (Tất nhiên, giả sử bạn có lý do chính đáng để chia hai loại nhân viên).

                 employee       
employees_ce     ————————       employees_sn
————————————     type           ————————————
empid —————————> empid <——————— empid
name               /|\          name
                    |  
                    |  
      deductions    |  
      ——————————    |  
      empid ————————+  
      name

typetrong bảng nhân viên sẽ là cehoặc sn.


Tôi đã thử thêm nhiều khóa ngoại, chúng hoạt động nhưng trong khi thêm bản ghi, java derby cho tôi biết cả hai ràng buộc khóa ngoại đều đã bị vi phạm!

Tôi vừa thử nó trên PostgreSQL, và nó hoạt động ở đó. Bạn có bản ghi gốc trong cả hai bảng không?
derobert

hồ sơ cha mẹ bạn muốn nói, trống rỗng?

Chắc chắn vấn đề đã được chuyển từ bảng "khấu trừ" sang bảng "nhân viên". Làm thế nào bạn sẽ tham chiếu các Đối tượng tiềm năng khác nhau dựa trên một loại?
gawpertron

1
@gawpertron: Chà, trống rỗng là duy nhất trên tất cả các loại. Bạn có thể sử dụng trường 'loại' để xem bảng phụ nào bạn cần tham chiếu. Hoặc chỉ LEFT JOINtất cả chúng, nếu có đủ ít. Khi không sử dụng bảng cơ sở 'worker', khóa chính không thể được khai báo (vì nó đang tham chiếu đến tableA hoặc tableB hoặc…); bây giờ nó có thể được. Sự khôn ngoan của việc tách employees_ceemployees_snđã được giả định, và giả định đó được ghi nhận.
derobert

19

Thực ra tôi tự làm việc này. Tôi có một bảng được gọi là 'Nhận xét' chứa các nhận xét cho các bản ghi trong 3 bảng khác. Không giải pháp nào thực sự xử lý được mọi thứ bạn có thể muốn. Trong trường hợp của bạn, bạn sẽ làm điều này:

Giải pháp 1:

  1. Thêm trường tinyint vào Employ_ce và Employ_sn có giá trị mặc định khác nhau trong mỗi bảng (Trường này đại diện cho 'mã nhận dạng bảng', vì vậy chúng tôi sẽ gọi chúng là tid_ce & tid_sn)

  2. Tạo Chỉ mục duy nhất trên mỗi bảng bằng cách sử dụng PK của bảng và trường id bảng.

  3. Thêm trường tinyint vào bảng 'Các khoản khấu trừ' của bạn để lưu trữ nửa sau của khóa ngoại (ID bảng)

  4. Tạo 2 khóa ngoại trong bảng 'Các khoản khấu trừ' của bạn (Bạn không thể thực thi tính toàn vẹn tham chiếu, vì một trong hai khóa sẽ hợp lệ hoặc khóa kia ... nhưng không bao giờ cả hai:

    ALTER TABLE [dbo].[Deductions]  WITH NOCHECK ADD  CONSTRAINT [FK_Deductions_employees_ce] FOREIGN KEY([id], [fk_tid])
    REFERENCES [dbo].[employees_ce] ([empid], [tid])
    NOT FOR REPLICATION 
    GO
    ALTER TABLE [dbo].[Deductions] NOCHECK CONSTRAINT [FK_600_WorkComments_employees_ce]
    GO
    ALTER TABLE [dbo].[Deductions]  WITH NOCHECK ADD  CONSTRAINT [FK_Deductions_employees_sn] FOREIGN KEY([id], [fk_tid])
    REFERENCES [dbo].[employees_sn] ([empid], [tid])
    NOT FOR REPLICATION 
    GO
    ALTER TABLE [dbo].[Deductions] NOCHECK CONSTRAINT [FK_600_WorkComments_employees_sn]
    GO
    
    employees_ce
    --------------
    empid    name     tid
    khce1   prince    1
    
    employees_sn
    ----------------
    empid    name     tid 
    khsn1   princess  2
    
    deductions
    ----------------------
    id      tid       name  
    khce1   1         gold
    khsn1   2         silver         
    ** id + tid creates a unique index **

Giải pháp 2: Giải pháp này cho phép duy trì tính toàn vẹn của tham chiếu: 1. Tạo trường khóa ngoại thứ hai trong bảng 'Khoản khấu trừ', cho phép giá trị Null trong cả khóa ngoại và tạo khóa ngoại bình thường:

    employees_ce
    --------------
    empid   name
    khce1   prince 

    employees_sn
    ----------------
    empid   name     
    khsn1   princess 

    deductions
    ----------------------
    idce    idsn      name  
    khce1   *NULL*    gold
    *NULL*  khsn1     silver         

Tính toàn vẹn chỉ được kiểm tra nếu cột không rỗng, vì vậy bạn có thể duy trì tính toàn vẹn tham chiếu.


6

Tôi biết đây là một chủ đề trì trệ từ lâu, nhưng trong trường hợp có ai đó tìm kiếm ở đây thì tôi sẽ xử lý như thế nào với các khóa ngoại nhiều bảng. Với kỹ thuật này, bạn không có bất kỳ hoạt động xếp tầng bắt buộc nào của DBA, vì vậy hãy đảm bảo rằng bạn xử lý DELETEvà tương tự trong mã của mình.

Table 1 Fruit
pk_fruitid, name
1, apple
2, pear

Table 2 Meat
Pk_meatid, name
1, beef
2, chicken

Table 3 Entity's
PK_entityid, anme
1, fruit
2, meat
3, desert

Table 4 Basket (Table using fk_s)
PK_basketid, fk_entityid, pseudo_entityrow
1, 2, 2 (Chicken - entity denotes meat table, pseudokey denotes row in indictaed table)
2, 1, 1 (Apple)
3, 1, 2 (pear)
4, 3, 1 (cheesecake)

SO Op's Ví dụ sẽ giống như thế này

deductions
--------------
type    id      name
1      khce1   gold
2      khsn1   silver

types
---------------------
1 employees_ce
2 employees_sn

1

Về mặt kỹ thuật có thể. Có thể bạn sẽ tham chiếu tới các khoản giảm trừ NLĐ_ce và NLĐ_sn. Nhưng tại sao bạn không hợp nhất nhân viên_sn và nhân viên_công ty? Tôi không hiểu tại sao bạn có hai bàn. Không có một mối quan hệ nhiều. Và (không phải trong ví dụ này) nhiều cột.

Nếu bạn thực hiện hai tham chiếu cho một cột, một nhân viên phải có một mục trong cả hai bảng.


1

Có, nó là có thể. Bạn sẽ cần xác định 2 FK cho bảng thứ 3. Mỗi FK trỏ đến (các) trường bắt buộc của một bảng (tức là 1 FK cho mỗi bảng ngoại).


0

Giả sử bạn phải có hai bảng cho hai loại nhân viên vì lý do nào đó, tôi sẽ mở rộng câu trả lời của vmarquez:

Lược đồ:

employees_ce (id, name)
employees_sn (id, name)
deductions (id, parentId, parentType, name)

Dữ liệu trong các khoản khấu trừ:

deductions table
id      parentId      parentType      name
1       1             ce              gold
2       1             sn              silver
3       2             sn              wood
...

Điều này sẽ cho phép bạn có các khoản khấu trừ trỏ đến bất kỳ bảng nào khác trong lược đồ của bạn. Loại mối quan hệ này không được hỗ trợ bởi các ràng buộc cấp cơ sở dữ liệu, IIRC, vì vậy bạn sẽ phải đảm bảo Ứng dụng của mình quản lý ràng buộc đúng cách (điều này khiến nó trở nên cồng kềnh hơn nếu bạn có nhiều Ứng dụng / dịch vụ khác nhau sử dụng cùng một cơ sở dữ liệu).

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.