it-swarm-id.com

Kunci Asing ke beberapa tabel

Saya punya 3 tabel yang relevan di database saya.

CREATE TABLE dbo.Group
(
    ID int NOT NULL,
    Name varchar(50) NOT NULL
)  

CREATE TABLE dbo.User
(
    ID int NOT NULL,
    Name varchar(50) NOT NULL
)

CREATE TABLE dbo.Ticket
(
    ID int NOT NULL,
    Owner int NOT NULL,
    Subject varchar(50) NULL
)

Pengguna termasuk dalam beberapa grup. Ini dilakukan melalui hubungan banyak ke banyak, tetapi tidak relevan dalam kasus ini. Tiket dapat dimiliki oleh grup atau pengguna, melalui bidang dbo.Ticket.Owner.

Apa yang akan menjadi PALING BENAR cara menggambarkan hubungan ini antara tiket dan opsional pengguna atau grup?

Saya berpikir bahwa saya harus menambahkan bendera di tabel tiket yang menyatakan jenis apa yang memilikinya.

109
Darthg8r

Anda memiliki beberapa opsi, semuanya bervariasi dalam "kebenaran" dan kemudahan penggunaan. Seperti biasa, desain yang tepat tergantung pada kebutuhan Anda.

  • Anda cukup membuat dua kolom di Ticket, OwnedByUserId dan OwnedByGroupId, dan memiliki kunci asing yang dapat dibatalkan untuk setiap tabel.

  • Anda dapat membuat tabel referensi M: M yang memungkinkan hubungan tiket: pengguna dan tiket: grup. Mungkin di masa depan Anda ingin mengizinkan satu tiket dimiliki oleh banyak pengguna atau grup? Desain ini tidak menegaskan bahwa tiket harus dimiliki oleh satu entitas saja.

  • Anda dapat membuat grup default untuk setiap pengguna dan memiliki tiket yang hanya dimiliki oleh Grup sejati atau Grup default Pengguna.

  • Atau (pilihan saya) memodelkan entitas yang bertindak sebagai basis untuk Pengguna dan Grup, dan memiliki tiket yang dimiliki oleh entitas itu.

Inilah contoh kasar menggunakan skema Anda yang diposting:

create table dbo.PartyType
(   
    PartyTypeId tinyint primary key,
    PartyTypeName varchar(10)
)

insert into dbo.PartyType
    values(1, 'User'), (2, 'Group');


create table dbo.Party
(
    PartyId int identity(1,1) primary key,
    PartyTypeId tinyint references dbo.PartyType(PartyTypeId),
    unique (PartyId, PartyTypeId)
)

CREATE TABLE dbo.[Group]
(
    ID int primary key,
    Name varchar(50) NOT NULL,
    PartyTypeId as cast(2 as tinyint) persisted,
    foreign key (ID, PartyTypeId) references Party(PartyId, PartyTypeID)
)  

CREATE TABLE dbo.[User]
(
    ID int primary key,
    Name varchar(50) NOT NULL,
    PartyTypeId as cast(1 as tinyint) persisted,
    foreign key (ID, PartyTypeId) references Party(PartyID, PartyTypeID)
)

CREATE TABLE dbo.Ticket
(
    ID int primary key,
    [Owner] int NOT NULL references dbo.Party(PartyId),
    [Subject] varchar(50) NULL
)
135
Nathan Skerl

Opsi pertama dalam daftar @ Nathan Skerl adalah apa yang diimplementasikan dalam proyek yang pernah saya kerjakan, di mana hubungan yang sama dibuat antara tiga tabel. (Salah satu dari mereka mereferensikan dua orang lain, satu per satu.)

Jadi, tabel referensi memiliki dua kolom kunci asing, dan juga memiliki kendala untuk menjamin bahwa satu tabel (bukan keduanya, bukan keduanya) dirujuk oleh satu baris.

Begini tampilannya saat diterapkan ke tabel Anda:

CREATE TABLE dbo.[Group]
(
    ID int NOT NULL CONSTRAINT PK_Group PRIMARY KEY,
    Name varchar(50) NOT NULL
);

CREATE TABLE dbo.[User]
(
    ID int NOT NULL CONSTRAINT PK_User PRIMARY KEY,
    Name varchar(50) NOT NULL
);

CREATE TABLE dbo.Ticket
(
    ID int NOT NULL CONSTRAINT PK_Ticket PRIMARY KEY,
    OwnerGroup int NULL
      CONSTRAINT FK_Ticket_Group FOREIGN KEY REFERENCES dbo.[Group] (ID),
    OwnerUser int NULL
      CONSTRAINT FK_Ticket_User  FOREIGN KEY REFERENCES dbo.[User]  (ID),
    Subject varchar(50) NULL,
    CONSTRAINT CK_Ticket_GroupUser CHECK (
      CASE WHEN OwnerGroup IS NULL THEN 0 ELSE 1 END +
      CASE WHEN OwnerUser  IS NULL THEN 0 ELSE 1 END = 1
    )
);

Seperti yang Anda lihat, tabel Ticket memiliki dua kolom, OwnerGroup dan OwnerUser, keduanya merupakan kunci asing yang tidak dapat dibatalkan. (Kolom masing-masing di dua tabel lainnya dibuat kunci utama yang sesuai.) Batasan periksa CK_Ticket_GroupUser memastikan bahwa hanya satu dari dua kolom kunci asing yang berisi referensi (yang lainnya NULL, karena itu keduanya harus nullable ).

(Kunci utama pada Ticket.ID tidak diperlukan untuk implementasi khusus ini, tetapi pasti tidak ada salahnya memiliki satu di tabel seperti ini.)

27
Andriy M

Namun pilihan lain adalah memiliki, dalam Ticket, satu kolom yang menentukan jenis entitas yang memiliki (User atau Group), kolom kedua dengan referensi User atau Group id dan TIDAK menggunakan Kunci Asing tetapi alih-alih mengandalkan Pemicu untuk menegakkan integritas referensial.

Dua kelebihan yang saya lihat di sini dibandingkan Nathan model luar biasa (di atas):

  • Lebih jelas dan sederhana.
  • Permintaan lebih sederhana untuk ditulis.
0
Jan Żankowski