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 kolom dbo.Ticket.Owner.
Cara apa yang PALING BENAR menggambarkan hubungan antara tiket dan secara opsional pengguna atau grup?
Saya berpikir bahwa saya harus menambahkan bendera di tabel tiket yang mengatakan jenis apa yang memilikinya.
sql-server
relational-database
Darthg8r
sumber
sumber
Jawaban:
Anda memiliki beberapa pilihan, semuanya bervariasi dalam "kebenaran" dan kemudahan penggunaan. Seperti biasa, desain yang tepat bergantung pada kebutuhan Anda.
Anda cukup membuat dua kolom di Ticket, OwnedByUserId dan OwnedByGroupId, dan memiliki Kunci Asing nullable untuk setiap tabel.
Anda dapat membuat tabel referensi M: M yang mengaktifkan hubungan tiket: pengguna dan tiket: grup. Mungkin di masa mendatang Anda ingin mengizinkan satu tiket dimiliki oleh banyak pengguna atau grup? Desain ini tidak memaksakan bahwa tiket harus dimiliki oleh satu entitas saja.
Anda dapat membuat grup default untuk setiap pengguna dan memiliki tiket yang hanya dimiliki oleh Grup sebenarnya atau Grup default Pengguna.
Atau (pilihan saya) membuat model entitas yang bertindak sebagai basis untuk Pengguna dan Grup, dan memiliki tiket yang dimiliki oleh entitas tersebut.
Berikut adalah contoh kasar menggunakan skema yang Anda posting:
sumber
SELECT t.Subject AS ticketSubject, CASE WHEN u.Name IS NOT NULL THEN u.Name ELSE g.Name END AS ticketOwnerName FROM Ticket t INNER JOIN Party p ON t.Owner=p.PartyId LEFT OUTER JOIN User u ON u.ID=p.PartyId LEFT OUTER JOIN Group g on g.ID=p.PartyID;
. Hasilnya, Anda akan memiliki semua subjek tiket dan nama pemilik.Opsi pertama dalam daftar @Nathan Skerl adalah apa yang diimplementasikan dalam proyek yang pernah saya tangani, di mana hubungan serupa dibuat antara tiga tabel. (Salah satunya mereferensikan dua lainnya, satu per satu.)
Jadi, tabel referensi memiliki dua kolom kunci asing, dan juga memiliki batasan untuk menjamin bahwa tepat satu tabel (tidak keduanya, tidak keduanya) direferensikan oleh satu baris.
Berikut tampilannya saat diterapkan ke tabel Anda:
Seperti yang Anda lihat,
Ticket
tabel memiliki dua kolom,OwnerGroup
danOwnerUser
, keduanya merupakan kunci asing yang dapat dinihilkan. (Kolom masing-masing di dua tabel lainnya dibuat sebagai kunci utama.)CK_Ticket_GroupUser
Batasan pemeriksaan memastikan bahwa hanya satu dari dua kolom kunci asing yang berisi referensi (yang lainnya adalah NULL, itulah mengapa keduanya harus nullable).(Kunci utama pada
Ticket.ID
tidak diperlukan untuk penerapan khusus ini, tetapi pasti tidak ada salahnya untuk memilikinya di tabel seperti ini.)sumber
RefID
,RefType
di manaRefType
merupakan identifier tetap tabel target. Jika Anda membutuhkan integritas, Anda dapat melakukan pemeriksaan di pemicu atau lapisan aplikasi. Pengambilan generik dimungkinkan dalam kasus ini. SQL harus mengizinkan definisi FK seperti ini, membuat hidup kita lebih mudah.Namun opsi lain adalah memiliki, di
Ticket
, satu kolom yang menentukan jenis entitas pemilik (User
atauGroup
), kolom kedua dengan referensiUser
atauGroup
id dan TIDAK menggunakan Kunci Asing melainkan mengandalkan Pemicu untuk menegakkan integritas referensial.Dua keunggulan yang saya lihat di sini dibandingkan model Nathan yang luar biasa (di atas):
sumber
Pendekatan lain adalah membuat tabel asosiasi yang berisi kolom untuk setiap jenis sumber daya potensial. Dalam contoh Anda, masing-masing dari dua tipe pemilik yang ada memiliki tabelnya sendiri (yang berarti Anda memiliki sesuatu untuk dirujuk). Jika ini akan selalu terjadi, Anda dapat memiliki sesuatu seperti ini:
Dengan solusi ini, Anda akan terus menambahkan kolom baru saat Anda menambahkan entitas baru ke database dan Anda akan menghapus serta membuat ulang pola batasan kunci asing yang ditunjukkan oleh @Nathan Skerl. Solusi ini sangat mirip dengan @Nathan Skerl tetapi terlihat berbeda (tergantung preferensi).
Jika Anda tidak akan memiliki Tabel baru untuk setiap jenis Pemilik baru, maka mungkin akan lebih baik untuk menyertakan tipe_milik daripada kolom kunci asing untuk setiap Pemilik potensial:
Dengan metode di atas, Anda dapat menambahkan Jenis Pemilik sebanyak yang Anda inginkan. Owner_ID tidak akan memiliki batasan kunci asing tetapi akan digunakan sebagai referensi ke tabel lain. Kelemahannya adalah Anda harus melihat tabel untuk melihat apa tipe pemiliknya karena tidak segera terlihat berdasarkan skema. Saya hanya akan menyarankan ini jika Anda tidak mengetahui jenis pemilik sebelumnya dan mereka tidak akan ditautkan ke tabel lain. Jika Anda mengetahui tipe pemilik sebelumnya, saya akan menggunakan solusi seperti @Nathan Skerl.
Maaf jika saya salah SQL, saya baru saja menyatukannya.
sumber
Saya pikir itu akan menjadi cara paling umum untuk mewakili apa yang Anda inginkan daripada menggunakan sebuah bendera.
sumber