2010-10-22 14 views
5

Questa domanda è comparsa un paio di volte in vari forum nella mia ricerca, ma nessuna ha fornito una risoluzione concisa.Tabelle di database, una tabella che fa riferimento a più tabelle non correlate

Se ho le seguenti tabelle:

User 
+- id 
+- username 
+- password 

Article 
+- id 
+- title 
+- content 

e voglio unirmi a loro, al fine di determinare chi ha creato quello articoli, si potrebbe semplicemente aggiungere la colonna user_id a articolo da utilizzare come riferimento. In alternativa, sto aggiungendo una tabella intermedia per mostrare che/quando/ciò che, ad esempio:

User 
+- ... 

Article 
+- ... 

ChangeHistory 
+- id 
+- article_id 
+- user_id 
+- type [enum(insert, update, delete)] 
+- datetime 

Ora questo va bene, ma il sistema su cui sto lavorando ha bisogno di essere molto più dinamico, in quella nuova i moduli possono essere facilmente introdotti e integrati. Così ora se posso aggiungere un Media tavolo ho bisogno di dividere il ChangeHistory tra articolo e media avere:

User 
+- ... 

Article 
+- ... 

Media 
+- id 
+- title 
+- path 

ArticleChangeHistory 
+- id 
+- article_id 
+- user_id 
+- type [enum(insert, update, delete)] 
+- datetime 

MediaChangeHistory 
+- id 
+- media_id 
+- user_id 
+- type [enum(insert, update, delete)] 
+- datetime 

Questo può sfuggire di mano rapidamente con l'introduzione di molti moduli. Ogni modulo dovrebbe essere responsabile della creazione e gestione della propria tabella ChangeHistory.

TL; DR: Quali pratiche posso esplorare per creare una tabella intermedia in grado di ricevere riferimenti a più tabelle non correlate? Potrei aggiungere un campo * record_type *, tenendo il nome della tabella a cui appartiene il record, ma è brutto. Avrei bisogno di qualcosa tipo "ID tavolo" per fare riferimento alla tabella da cui proviene. In questo modo, quando i moduli/se vengono aggiunti o rimossi, il modello non va in pezzi.

Qualche idea? Grazie mille in anticipo.

+0

C'è qualche motivo per cui consideri un "ID tabella" migliore di "record_type"? –

risposta

4

Nella mia esperienza, quando gli sviluppatori cercano di fare il loro sistema realmente "dinamico" che stanno in realtà cercando di codificare per problemi che non hanno ancora pensato. Di solito è una cattiva strada da percorrere. È davvero così tanto lavoro extra per un modulo includere due tabelle invece di una?

In tutti i casi in cui ho visto il modello (o anti-pattern?) Del tentativo di rendere generico un tavolo "fa tutto", è caduto in superficie. I RDBMS funzionano meglio con aree problematiche ben definite. Se il modulo ha bisogno di conservare la cronologia, il modulo dovrebbe aggiungere una tabella della cronologia per andare con la tabella stessa. Questo ha anche un enorme vantaggio in quanto è probabile che vogliate mantenere diversi tipi di informazioni nella cronologia a seconda della tabella o del modulo per il quale viene conservata la cronologia. Se hai una tabella di cronologia generica diventa molto più difficile.

Ora, se si desidera semplicemente acquisire l'ultimo utente per aggiornare o inserire un particolare oggetto (riga della tabella) e che potrebbe essere in più tabelle, è possibile utilizzare un modello di ereditarietà in cui si dispone di una tabella padre e di più figli tabelle. Per esempio:

CREATE TABLE Audited_Items 
(
    id INT NOT NULL IDENTITY, 
    CONSTRAINT PK_Audited_Items PRIMARY KEY CLUSTERED (id) 
) 
CREATE TABLE Articles 
(
    id INT   NOT NULL, 
    [Article specific columns] 
    CONSTRAINT PK_Articles PRIMARY KEY CLUSTERED (id), 
    CONSTRAINT FK_Articles_Audited_Items FOREIGN KEY (id) REFERENCES Audited_Items (id) 
) 
CREATE TABLE Media 
(
    id INT   NOT NULL, 
    [Media specific columns] 
    CONSTRAINT PK_Media PRIMARY KEY CLUSTERED (id), 
    CONSTRAINT FK_Media_Audited_Items FOREIGN KEY (id) REFERENCES Audited_Items (id) 
) 
CREATE TABLE Audit_Trail 
(
    audited_item_id INT   NOT NULL, 
    audit_datetime  DATETIME NOT NULL, 
    user_id   INT   NOT NULL, 
    [audit columns] 
    CONSTRAINT PK_Audit_Trail PRIMARY KEY CLUSTERED (audited_item_id, audit_datetime), 
    CONSTRAINT FK_Audit_Trail_Audited_Items FOREIGN KEY (audited_item_id) REFERENCES Audited_Items (id) 
) 
+0

Grazie per la tua risposta dettagliata Tom. Mi piace molto questo progetto e lo considererò nelle mie ulteriori ricerche. – Dan

+0

Chiudendo il ciclo sulla domanda, grazie Tom H., il tuo metodo sembra soddisfare abbastanza bene il mio progetto. Speriamo che pochi cambiamenti dovranno essere fatti lungo la strada. – Dan

2

Mi sembra che tu stia chiedendo una guida che ti conduca lungo un percorso tortuoso e spinoso.

Non so perché è necessario aggiungere una nuova tabella ogni volta che si ottiene un nuovo "modulo" (non mi è chiaro che cos'è un modulo) a condizione che i moduli possano essere tutti descritti con lo stesso layout di colonna . È possibile aggiungere una tabella Modules e quindi includere una colonna ModuleId nella tabella Articoli.

Inoltre, gli articoli possono avere più di un autore, quindi se lo fai, ti serve una tabella ArticleAuthors. E in alcuni ambienti, l'ordine degli autori su un articolo è importante. È una classifica dell'importanza del loro contributo o della loro importanza nel campo. In questo caso, dovresti avere una colonna "ordinale" per riflettere la posizione dell'autore.

+0

Grazie per la tua risposta rapida Tim; I moduli rappresentano i sottosistemi di un CMS su cui sto lavorando. Più autori di un articolo possono essere rappresentati dall'autore dell'autore originale e successive modifiche dell'autore. Gli utenti sono classificati per livello (non ho incluso molti campi irrilevanti nei miei modelli di esempio per motivi di semplicità) Ho sperato di trovare una sorta di soluzione "table-ID", cioè indipendente dal modello stesso ... – Dan

+1

Per espandere un po 'di più, ho una tabella Modules, per registrare e annullare la registrazione dei moduli (e contenere i parametri di configurazione, ecc.) Ma un Modulo può avere più tabelle, come Discografia con Traccia e Album. Sia la traccia che l'album necessitavano di singole tabelle ChangeHistory (o riferimenti in una tabella intermedia comune) e pertanto un singolo module_id non sarebbe sufficiente per fare riferimento sia alla traccia che all'album. – Dan

2

Penso che potrebbe essere meglio con una singola tabella ChangeHistory che sembra qualcosa di simile: (es. Articolo, media, ecc ...)

 
ItemChangeHistory 
+- id 
+- changedItem_id 
+- user_id 
+- changedItemType_id 
+- type [enum(insert, update, delete)] 
+- datetime 

e quindi utilizzare changedItemType_id per capire cosa è stato modificato basato su una tabella itemType. In questo modo hai solo una tabella per tutte le cronologie di modifica del contenuto e non devi aggiungere/rimuovere tabelle quando aggiungi/rimuovi moduli, semplicemente aggiorni la tabella itemType.Ovviamente questo significa che la rimozione di un modulo deve essere fatta con attenzione - potresti lasciare indietro i record ItemChangeHistory che fanno riferimento al tipo di quel modulo (ma è disordinato) o rimuovere tutta la cronologia associata al modulo.


Ora si parla di un modulo può avere altri tavoli, così forse quelli devono essere monitorati con un ID di modulo, si fa riferimento anche a ItemChangeHistory?

0

Perché non

ChangeHistory 
+- id 
+- content_id 
+- content_type 
+- user_id 
+- action [enum(added, updated, deleted)] 
+- datetime 
0

@Majid: Capisco che è probabilmente la soluzione più ragionevole, ma speravo di trovare qualcosa di un po 'più intuitivo, qualcosa che potrebbe potenzialmente trarre vantaggio dei parametri DB esistenti; come l'ID di tabella elusivo (e chiaramente inesistente) (con cui intendo una sorta di riferimento interno che il motore, InnoDB nel mio caso usa per descrivere le tabelle)

@ frustrato: Suppongo di essere sta andando per andare con qualcosa di simile. Continuerò a indagare sulle possibilità.

Problemi correlati