Memodelkan struktur basis data untuk beberapa tipe pengguna dan informasi kontak mereka

10

Saya merancang basis data yang akan menyimpan pengguna dari berbagai jenis. Secara dominan (tetapi tidak secara eksklusif) mereka akan menjadi Aktor, Direktur dan Penulis. Saat ini hanya ada empat jenis pengguna yang relevan. Ada kemungkinan di luar bahwa jumlah ini dapat meningkat, tetapi kemungkinannya rendah - dan dalam kasus seperti itu akan menjadi jumlah yang sangat kecil.

Rencananya adalah memiliki userstabel yang bertanggung jawab cukup banyak hanya untuk masuk ke situs ( name, emaildan passwordkolom ditambah satu atau dua lainnya seperti apakah mereka telah disetujui, dan updated_at), dan tabel tambahan untuk masing-masing jenis pengguna masing-masing yang masing-masing memiliki kumpulan kolom mereka sendiri yang unik. Hanya aktor, misalnya, yang akan memiliki kolom etnis, hanya Direktur yang memiliki kolom bio, dan hanya Penulis yang perlu menyediakan lokasi mereka. Namun, karena saya belum pernah mengelola database kompleksitas ini sebelumnya, saya ingin tahu bagaimana mengatur beberapa aspek:

Pertama, pengguna dapat berupa salah satu, atau kombinasi apa pun, dari jenis di atas. Jadi saya mengerti saya akan membutuhkan sesuatu seperti (misalnya) director_usertabel dengan director_iddan user_idkolom. Apakah ini cukup untuk dapat memfilter semua pengguna berdasarkan tipe peran dan seterusnya?

Kedua, sebagian besar pengguna akan memilih profil dan nomor telepon twitter. Dan semua aktor harus memasukkan setidaknya satu URL untuk profil aktor daring lainnya; saat ini ada tiga yang dapat mereka sertakan, tetapi jumlah ini dapat meningkat. Apakah saya benar berasumsi bahwa tabel terpisah untuk masing-masing profil yang mungkin / metode kontak adalah cara yang optimal untuk mengatur data?

Verisme
sumber

Jawaban:

14

Menurut interpretasi saya tentang deskripsi Anda tentang konteks bisnis yang menarik, Anda berhadapan dengan struktur supertipe-subtipe 1 di mana (a) Aktor , Direktur , dan Penulis adalah subtipe entitas dari (b) Orang , supertipe entitas mereka, dan (c) kata subtipe tidak saling eksklusif.

Dengan cara ini, jika Anda tertarik dalam membangun relasional database yang cermin skenario seperti itu akurat -dan karenanya mengharapkan bahwa itu berfungsi sebagai such-, Anda mengikuti klarifikasi komentar yang cukup signifikan sehubungan dengan poin sebelumnya, karena mereka memiliki implikasi pada keduanya (1) konseptual dan (2) tingkat representasi logis dari database yang dimaksud:

  • […] Tabel tambahan untuk masing-masing jenis pengguna masing-masing yang masing-masing memiliki kumpulan kolom unik mereka sendiri.

  • [...] hanya ada empat tipe pengguna yang relevan. Ada kemungkinan di luar bahwa jumlah ini dapat meningkat, tetapi kemungkinannya rendah - dan dalam kasus seperti itu akan menjadi jumlah yang sangat kecil.

Saya akan menguraikan semua aspek tersebut dan beberapa faktor penting lainnya di bagian di bawah ini.

Peraturan bisnis

Dalam rangka untuk pertama mendefinisikan skema konseptual yang sesuai -yang dapat digunakan sebagai referensi berikutnya sehingga Anda dapat menyesuaikan untuk memastikan bahwa memenuhi tepat persyaratan- informasi, saya telah merumuskan beberapa aturan bisnis yang penting:

  • Sebuah Orang dapat melakukan satu-dua atau tiga (yaitu, satu-ke-semua) Peran 2 . Dengan kata lain, Seseorang mungkin
    • seorang Aktor dan
    • seorang Direktur dan
    • seorang Penulis .
  • Sebuah Orang dapat log in melalui nol-atau-satu UserProfile .
  • Seorang Aktor menyediakan satu-dua atau tiga URL 3 .
  • Seorang Aktor dikelompokkan oleh satu Etnisitas .
  • Sebuah Etnis kelompok nol-satu-atau-banyak Actors .
  • Seorang Penulis berbasis di satu Lokasi .
  • Sebuah Lokasi adalah dasar dari nol-satu-atau-lebih Writers .

Diagram Eksposisi IDEF1X

Kemudian, saya membuat diagram IDEF1X 4 yang ditunjukkan pada Gambar 1 , yang mengelompokkan semua formulasi di atas bersama dengan aturan lain yang muncul terkait:

Gambar 1 - Diagram IDEF1X untuk Peran Orang dan Detail Kontak di Bioskop

Seperti yang ditunjukkan, Person supertype (i) memiliki kotaknya sendiri, (ii) memiliki properti atau atribut yang berlaku untuk semua subtipe, dan (iii) menyajikan garis yang menghubungkannya dengan kotak-kotak dari setiap subtipe.

Pada gilirannya, setiap subtipe (a) muncul di kotak khusus sendiri, dan (b) memiliki sifat eksklusif yang berlaku. KUNCI UTAMA dari supertype, PersonId , bermigrasi 5 ke subtipe dengan nama peran 6 ActorId , DirectorId , dan WriterId masing-masing .

Juga, saya menghindari menggabungkan Orang dengan tipe entitas UserProfile , yang memungkinkan memisahkan semua implikasi kontekstual, asosiasi atau hubungan mereka, dll. Properti PersonId telah dimigrasi ke UserProfile dengan nama peran UserId .

Anda menyatakan di badan pertanyaan itu

Dan semua aktor harus memasukkan setidaknya satu URL untuk profil aktor daring lainnya; saat ini ada tiga yang dapat mereka sertakan, tetapi jumlah ini dapat meningkat.

... jadi URL adalah jenis entitas dalam haknya sendiri, dan secara langsung dikaitkan dengan subtipe Aktor sesuai dengan kutipan ini.

Dan, dalam komentar , Anda menentukan itu

[...] seorang aktor akan memiliki headshot (foto), sementara seorang penulis tidak akan [...]

... lalu, di antara fitur-fitur lainnya, saya memasukkan Headshot sebagai properti dari tipe entitas Aktor .

Adapun jenis entitas Etnis dan Lokasi , mereka tentu saja mungkin memerlukan organisasi yang lebih kompleks (misalnya, Aktor mungkin milik satu, dua atau lebih kelompok etnis yang berbeda dalam proporsi yang berbeda, dan Penulis dapat didasarkan pada tempat yang membutuhkan pencatatan negara, wilayah administratif, county, dll.) tetapi sepertinya kebutuhan konteks bisnis Anda berhasil dicakup dengan struktur yang dibuat di sini.

Secara alami, Anda dapat membuat penyesuaian sebanyak yang diperlukan.

Ilustrasi desain logis SQL-DDL

Akibatnya, berdasarkan pada diagram IDEF1X yang ditunjukkan dan dijelaskan di atas, saya menulis tata letak logis DDL yang ditunjukkan sebagai berikut (Saya telah memberikan catatan sebagai komentar yang menjelaskan beberapa karakteristik yang saya hargai terutama penting sehubungan dengan tabel, kolom dan batasan dinyatakan):

-- You should determine which are the most fitting 
-- data types and sizes for all your table columns 
-- depending on your business context characteristics.

-- Also, you should make accurate tests to define the 
-- most convenient INDEX strategies based on the exact 
-- data manipulation tendencies of your business needs.

-- As one would expect, you are free to utilize 
-- your preferred (or required) naming conventions. 

CREATE TABLE Person ( -- Represents the supertype.
    PersonId       INT      NOT NULL,
    FirstName      CHAR(30) NOT NULL,
    LastName       CHAR(30) NOT NULL,
    BirthDate      DATE     NOT NULL,
    GenderCode     CHAR(3)  NOT NULL,
    TwitterProfile CHAR(30) NOT NULL,
    PhoneNumber    CHAR(30) NOT NULL,
    EmailAddress   CHAR(30) NOT NULL,  
    CreatedDateTime DATETIME NOT NULL,
    --
    CONSTRAINT Person_PK  PRIMARY KEY (PersonId),
    CONSTRAINT Person_AK1 UNIQUE ( -- Composite ALTERNATE KEY.
        FirstName,
        LastName,
        GenderCode,
        BirthDate
    ),
    CONSTRAINT Person_AK2 UNIQUE (TwitterProfile), -- ALTERNATE KEY.
    CONSTRAINT Person_AK3 UNIQUE (EmailAddress)    -- ALTERNATE KEY.
);

CREATE TABLE Ethnicity ( -- Its rows will serve a “look-up” purpose.
    EthnicityId     INT      NOT NULL,
    Name            CHAR(30) NOT NULL,  
    Description     CHAR(30) NOT NULL,
    CreatedDateTime DATETIME NOT NULL,
    -- 
    CONSTRAINT Ethnicity_PK PRIMARY KEY (EthnicityId),
    CONSTRAINT Ethnicity_AK UNIQUE      (Description)   
);

CREATE TABLE Actor ( -- Stands for one of the subtypes.
    ActorId         INT      NOT NULL, -- Must be constrained as (a) the PRIMARY KEY and (b) a FOREIGN KEY.
    Headshot        CHAR(30) NOT NULL, -- May, e.g., contain a URL indicating the path where the photo file is actually stored. 
    EthnicityId     INT      NOT NULL,
    CreatedDateTime DATETIME NOT NULL,
    -- 
    CONSTRAINT Actor_PK            PRIMARY KEY (ActorId),
    CONSTRAINT ActorToPerson_PK    FOREIGN KEY (ActorId)
        REFERENCES Person (PersonId),
    CONSTRAINT ActorToEthnicity_PK FOREIGN KEY (EthnicityId)
        REFERENCES Ethnicity (EthnicityId)   
);

CREATE TABLE Director ( -- Denotes one of the subtypes
    DirectorId      INT       NOT NULL, -- Must be constrained as (a) the PRIMARY KEY and (b) a FOREIGN KEY.
    Bio             CHAR(120) NOT NULL,  
    Etcetera        CHAR(30)  NOT NULL,
    CreatedDateTime DATETIME  NOT NULL,
    -- 
    CONSTRAINT Director_PK         PRIMARY KEY (DirectorId),
    CONSTRAINT DirectorToPerson_PK FOREIGN KEY (DirectorId)
        REFERENCES Person (PersonId)   
);

CREATE TABLE Country (
    CountryCode     CHAR(2)  NOT NULL,
    Name            CHAR(30) NOT NULL,  
    CreatedDateTime DATETIME NOT NULL,
    -- 
    CONSTRAINT Country_PK PRIMARY KEY (CountryCode),
    CONSTRAINT Country_AK UNIQUE      (Name)   
);

CREATE TABLE Location ( -- Its rows will serve a “look-up” purpose.
    CountryCode     CHAR(2)  NOT NULL,
    LocationCode    CHAR(3)  NOT NULL,
    Name            CHAR(30) NOT NULL,  
    CreatedDateTime DATETIME NOT NULL,
    -- 
    CONSTRAINT Location_PK PRIMARY KEY (CountryCode, LocationCode),
    CONSTRAINT Location_AK UNIQUE      (CountryCode, Name)   
);

CREATE TABLE Writer ( -- Represents one of the subtypes.
    WriterId        INT      NOT NULL, -- Must be constrained as (a) the PRIMARY KEY and (b) a FOREIGN KEY.
    CountryCode     CHAR(2)  NOT NULL,
    LocationCode    CHAR(3)  NOT NULL,
    CreatedDateTime DATETIME NOT NULL,
    -- 
    CONSTRAINT Writer_PK           PRIMARY KEY (WriterId),
    CONSTRAINT WriterToPerson_PK   FOREIGN KEY (WriterId)
        REFERENCES Person (PersonId),
    CONSTRAINT WriterToLocation_PK FOREIGN KEY (CountryCode, LocationCode)
        REFERENCES Location (CountryCode, LocationCode)  
);

CREATE TABLE UserProfile (
    UserId          INT      NOT NULL, -- Must be constrained as (a) the PRIMARY KEY and (b) a FOREIGN KEY.
    UserName        CHAR(30) NOT NULL,
    Etcetera        CHAR(30) NOT NULL,
    CreatedDateTime DATETIME NOT NULL,
    -- 
    CONSTRAINT UserProfile_PK PRIMARY KEY (UserId),
    CONSTRAINT UserProfile_AK UNIQUE      (UserName), -- ALTERNATE KEY.
    CONSTRAINT UserProfileToPerson_PK FOREIGN KEY (UserId)
        REFERENCES Person (PersonId)    
);

CREATE TABLE URL (
    ActorId       INT      NOT NULL,
    Address       CHAR(90) NOT NULL,
    Etcetera      CHAR(30) NOT NULL,
    AddedDateTime DATETIME NOT NULL,
    -- 
    CONSTRAINT URL_PK        PRIMARY KEY (ActorId, Address), -- Composite PRIMARY KEY.
    CONSTRAINT URLtoActor_FK FOREIGN KEY (ActorId)
        REFERENCES Actor (ActorId)
);

Oleh karena itu, (1) setiap aspek tunggal dari tata letak logis di atas membawa makna yang sangat tepat dari (2) fitur tunggal dari lingkungan bisnis yang menarik 7 - dalam perjanjian dengan semangat kerangka kerja oleh Dr. Edgar Frank Codd -, karena:

  • Setiap tabel dasar mewakili tipe entitas individual.
  • Setiap kolom merupakan properti tunggal dari jenis entitas masing-masing.
  • Tipe data tertentu diperbaiki untuk setiap kolom untuk memastikan bahwa semua nilai yang dikandungnya milik set tertentu dan dibatasi dengan benar, baik itu INT, DATETIME, CHAR, dll. (Dan marilah kita berharap bahwa MySQL akhirnya akan menggabungkan DOMAIN dukungan dalam versi waktu dekat).
  • Beberapa kendala dikonfigurasikan (secara deklaratif) untuk menjamin bahwa asersi dalam bentuk baris yang dipertahankan dalam semua tabel mematuhi aturan bisnis yang ditentukan pada tingkat konseptual.
  • Setiap baris dimaksudkan untuk menyampaikan semantik yang didefinisikan dengan baik, misalnya, sebuah Personbaris dibaca

    Orang yang diidentifikasi oleh PersonId rdipanggil oleh FirstName sdan LastName t, lahir di BirthDate u, memiliki GenderCode v, tweet di TwitterProfile w, dijangkau melalui PhoneNumber x, dihubungi melalui EmailAddress y, dan terdaftar di CreatedDateTimez .

Memiliki tata letak seperti ini jelas menguntungkan, karena Anda dapat memperoleh tabel baru (mis., Operasi SELECT yang mengumpulkan kolom DARI beberapa tabel dengan bantuan klausa GABUNG) yang —dalam suksesi — membawa makna yang sangat tepat juga (lihat bagian berjudul "Tampilan" di bawah).

Perlu disebutkan bahwa, dengan konfigurasi ini, (i) baris yang mewakili turunan subtipe diidentifikasi oleh (ii) nilai KUNCI UTAMA yang sama yang membedakan baris yang menunjukkan kejadian supertipe pelengkap. Jadi, lebih dari cukup untuk mencatatnya

  • (a) melampirkan tambahan kolom untuk sistem yang dihasilkan ditahan dan sistem-ditugaskan pengganti 8 untuk (b) tabel berdiri untuk subtipe adalah (c) seluruhnya berlebihan .

Dengan desain logis ini, jika subtipe baru didefinisikan sebagai relevan dalam konteks bisnis Anda, Anda harus mendeklarasikan tabel dasar baru, tetapi itu terjadi juga ketika jenis entitas jenis lain dianggap penting, sehingga situasinya akan menjadi, dalam sebenarnya, biasa saja.

Tampilan

Untuk “mengambil”, misalnya, semua informasi yang terkait dengan Aktor , Direktur atau Penulis , Anda dapat mendeklarasikan beberapa tampilan (yaitu, tabel yang diturunkan atau dapat diungkapkan ) sehingga Anda dapat SELECT langsung dari satu sumber tunggal tanpa harus menulis tentang GABUNGAN setiap saat; misalnya, dengan TAMPILAN yang dinyatakan di bawah ini, Anda dapat memperoleh informasi Aktor "lengkap" :

--
CREATE VIEW FullActor AS

    SELECT P.FirstName,
           P.Lastname,
           P.BirthDate,
           P.GenderCode,
           P.TwitterProfile,
           P.PhoneNumber,
           P.EmailAddress,
           A.Headshot,
           E.Name AS Ethnicity
         FROM Person P
         JOIN Actor A
           ON A.ActorId     = P.PersonId
         JOIN Ethnicity E
           ON E.EthnicityId = A.EthnicityId;
--

Tentu saja, Anda dapat mengikuti pendekatan serupa untuk mendapatkan informasi Direktur dan Penulis yang "lengkap" :

--
CREATE VIEW FullDirector AS

    SELECT P.FirstName,
           P.Lastname,
           P.BirthDate,
           P.GenderCode,
           P.TwitterProfile,
           P.PhoneNumber,
           P.EmailAddress,
           D.Bio,
           D.Etcetera
         FROM Person P
         JOIN Director D
           ON D.DirectorId = P.PersonId; 

--
CREATE VIEW FullWriter AS

    SELECT P.FirstName,
           P.Lastname,
           P.BirthDate,
           P.GenderCode,
           P.TwitterProfile,
           P.PhoneNumber,
           P.EmailAddress,
           L.Name AS Location,
           C.Name AS Country
         FROM Person P
         JOIN Writer W
           ON W.WriterId     = P.PersonId
         JOIN Country C
           ON C.CountryCode  = W.CountryCode
         JOIN Location L
           ON L.LocationCode = W.LocationCode;   
--

Saya telah memposting semua pernyataan DDL dan tampilan DML di sini yang dibahas dalam SQL Fiddle ini berjalan pada MySQL 5.6 sehingga Anda dapat melihat dan mengujinya "dalam aksi".


Catatan akhir

1 Dalam beberapa teknik pemodelan konseptual, asosiasi supertipe-subtipe disebut sebagai hubungan superclass-subclass .

2 Meskipun Anda menyebutkan bahwa terdapat sebenarnya lebih Peran bahwa Orang dapat melakukan, tapi tiga Anda mengungkapkan cukup baik untuk membahas skenario mengekspos beberapa penting konsekuensi .

3 Tetapi, seperti yang Anda catat, di masa depan seorang Aktor mungkin pada akhirnya akan memberikan URL satu-ke-banyak .

4 Definisi Integrasi untuk Pemodelan Informasi ( IDEF1X ) adalah teknik pemodelan yang sangat direkomendasikan yang ditetapkan sebagai standar pada bulan Desember 1993 oleh Institut Standar dan Teknologi Nasional (NIST) Amerika Serikat . Ini didasarkan pada (a) karya teoritis awal yang ditulis oleh satu-satunya pencetus model data relasional, yaitu, Dr. EF Codd; pada (b) pandangan entitas-hubungan , yang dikembangkan oleh Dr. PP Chen ; dan juga pada (c) Teknik Desain Basis Data Logis, yang dibuat oleh Robert G. Brown.

5 Standar IDEF1X mendefinisikan migrasi kunci sebagai “Proses pemodelan menempatkan kunci primer dari entitas induk atau generik [yaitu, supertipe] dalam entitas anak atau kategorinya [yaitu subtipe] sebagai kunci asing”.

6 Dalam IDEF1X, nama peran adalah label khusus yang ditetapkan untuk atribut FK untuk mengekspresikan makna yang dipegangnya dalam lingkup jenis entitasnya masing-masing.

7 Kecuali, secara alami, untuk properti konseptual hipotetis (dan kolom logis) Direktur.Etcetera dan UserProfile.Etcetera , yang hanya placeholder yang saya gunakan untuk mengekspos kemungkinan menambahkan lebih banyak properti (dan kolom) yang berlaku untuk jenis entitas konseptual yang sesuai (dan tabel logis).

8 Misalnya, menambahkan kolom tambahan dengan atribut AUTO_INCREMENT ke tabel database "berjalan" di MySQL.

MDCCL
sumber
2

Anda harus membagi tabel ini menjadi seperti ini (hanya menunjukkan kolom yang diperlukan untuk mempresentasikan konsep, tidak harus semua kolom):

Users
ID   Username   FirstName   LastName   PasswordHash ...
 1   'Joe1'      'Joe'      'Smith'
 2   'Freddy'    'Fred'     'Jones'

Roles
ID   RoleType ....
 1   'Writer'
 2   'Director'
 3   'Actor'

User_Roles
User_ID   Role_ID ...
1         1
1         2
2         2
2         3

Ini memberi Anda tabel penuh pengguna dengan semua berbagai kolom pengguna, daftar peran, dan tabel penautan untuk menghubungkan keduanya.

Anda dapat melihat bahwa Joe1 adalah penulis dan sutradara oleh entri di User_Roles. Dan Freddy adalah seorang sutradara dan aktor.

Ini juga memungkinkan Anda untuk menambahkan lebih banyak peran nanti tanpa mengubah sistem. Cukup masukkan catatan untuk Produser atau Editor atau apa pun di telepon.

Jadi untuk menemukan semua nama pengguna aktor, Anda memiliki beberapa pilihan:

 Select Distinct Username
   from Users
  Where User_ID in (select User_ID from User_Roles where Role_ID = 3)

Atau jika Anda tidak tahu nomor role_ID, maka:

 Select Distinct Username
   from Users
  Where User_ID in (Select User_ID from User_Roles where Role_ID = 
                       (Select ID from Roles where RoleType = 'Actor')
                   )

Atau Anda juga dapat melakukan ini:

select u.Username, r.RoleType
  from Users u
 inner join User_Roles ur on ur.User_ID = u.ID
 inner join Roles r on r.ID = ur.Role_ID
 where r.RoleType = 'Actor'

(Dalam versi ini, Anda dapat menggunakan juga gunakan Where r.Role_ID = 3untuk mendapatkan hasil yang sama.)

Tapi saya akan menggunakan kueri 1 dan klausa WHERE mana yang saya tahu. Dalam sistem besar, mengetahui Role_ID akan, umumnya, berjalan lebih cepat daripada teks, karena data numerik "lebih mudah" dan lebih efisien bagi sebagian besar mesin SQL untuk memproses indeks.

Adapun metode kontak atau foto atau apa pun, saya akan melakukannya dengan cara yang sama:

Attributes
ID    MethodText    ...
1     'TwitterID'
2     'URL'
3     'CellPhone'
4     'Email'
5     'PictureLink'

Role_Attributes
Role_ID  Attribute_ID isRequired
3        5             1
3        4             1
3        3             0

User_Attributes
User_ID  Attribute_ID  AttributeData
1         4            '[email protected]'
1         1            '@joe'
1         3            '555-555-5555'
1         5            'www.example.com/pics/myFace.png'

...dan seterusnya. Ini akan terhubung dengan cara yang sama seperti pengguna ke peran.

Ini menunjukkan bahwa setiap peran memiliki 0 hingga banyak atribut, yang mungkin opsional. Kemudian setiap pengguna memiliki 0 hingga banyak atribut, dengan data untuk atribut tersebut.

Ini memungkinkan Anda menambahkan atribut baru seiring berjalannya waktu, tanpa menulis ulang kode apa pun; perbarui tabel atribut dan role_attributes agar sesuai dengan aturan baru Anda. Ini juga memungkinkan Anda berbagi atribut di antara peran, tanpa memasukkan kembali data yang sama untuk setiap pengguna. Jika dua peran memerlukan foto, maka mereka hanya perlu mengunggah 1 foto untuk memenuhi persyaratan itu.

CaM
sumber
Aha, saya pikir itu masuk akal dalam satu hal ... tapi saya tidak begitu jelas tentang bagaimana - misalnya - saya akan daftar semua aktor bersama, katakanlah, Nama pengguna mereka (dengan asumsi bahwa data aktor-y disimpan di tabel terpisah).
verism
Lihat hasil edit saya; Saya telah menambahkan contoh kueri.
CaM
Itu sangat membantu, terima kasih. Saya pikir saya mungkin belum sepenuhnya jelas dalam pertanyaan saya - maaf. Seharusnya saya membuatnya lebih jelas bahwa tabel untuk setiap jenis (Aktor, Direktur dll) akan memiliki atribut unik mereka sendiri yang relevan hanya untuk jenis pengguna itu. Misalnya, seorang aktor akan memiliki headshot (foto), sedangkan seorang Penulis tidak. Maaf sekali lagi untuk tidak lebih eksplisit tentang ini.
verism
Metode kontak tampaknya menjadi solusi hebat.
verism
1
Mengubahnya menjadi atribut, untuk memenuhi persyaratan untuk foto, dll. Seharusnya lebih cocok, sekarang.
CaM