2009-02-18 125 views
22

ho attualmente più tabelle nel mio database che consistono degli stessi 'campi base' come:Polimorfismo nelle tabelle del database SQL?

name character varying(100), 
description text, 
url character varying(255)

Ma avere più specializzazioni di quel tavolo di base, che è per esempio che tv_series ha i campi season, episode , airing, mentre il tavolo movies ha release_date, budget ecc

Ora in un primo momento questo non è un problema, ma voglio creare una seconda tabella, denominata linkgroups con una chiave esterna a queste tabelle specializzate. Ciò significa che in qualche modo dovrei normalizzarlo in se stesso.

Un modo per risolvere ciò che ho sentito è di normalizzarlo con una tabella di confronto key-value, ma non mi piace l'idea poiché è una specie di schema "database all'interno di un database", I non hanno un modo per richiedere determinati tasti/campi né richiedono un tipo speciale, e sarebbe un enorme problema recuperare e ordinare i dati in seguito.

Quindi sto cercando un modo per "condividere" una chiave primaria tra più tabelle o anche meglio: un modo per normalizzarlo avendo una tabella generale e più tabelle specializzate.

+0

Ok, non sono sicuro al 100% che sto leggendo bene. Hai un mucchio di tavoli disparati che hanno una struttura comune. Si desidera aggiungere una singola tabella che faccia riferimento a queste tabelle, ma non è possibile utilizzare un FK perché ogni tabella ha il proprio PK. Se è possibile, creerei un tavolo principale comune e lo appenderò. – Joe

+0

Sì, ma la mia domanda è esattamente come fare esattamente questo elegantemente –

risposta

24

Esatto, il problema è che si desidera che solo un oggetto di un sottotipo faccia riferimento a una determinata riga della classe padre. Partendo dal example data dal @Jay S, provate questo:

create table media_types (
    media_type  int primary key, 
    media_name  varchar(20) 
); 
insert into media_types (media_type, media_name) values 
    (2, 'TV series'), 
    (3, 'movie'); 

create table media (
    media_id  int not null, 
    media_type  not null, 
    name   varchar(100), 
    description text, 
    url   varchar(255), 
    primary key (media_id, media_type), 
    foreign key (media_type) 
    references media_types (media_type) 
); 

create table tv_series (
    media_id  int primary key, 
    media_type  int check (media_type = 2), 
    season   int, 
    episode  int, 
    airing   date, 
    foreign key (media_id, media_type) 
    references media (media_id, media_type) 
); 

create table movies (
    media_id  int primary key, 
    media_type  int check (media_type = 3), 
    release_date date, 
    budget   numeric(9,2), 
    foreign key (media_id, media_type) 
    references media (media_id, media_type) 
); 

Questo è un esempio di sottotipi disgiunti mentioned di @ Mike g.


Re commenti di @Countably Infinito e @Peter:

Inserisci per due tavoli richiederebbe due istruzioni INSERT. Ma questo è vero anche in SQL ogni volta che si hanno tabelle figlio. È una cosa normale da fare.

UPDATE può richiedere due istruzioni, ma alcune marche di RDBMS supportano l'AGGIORNAMENTO a più tabelle con la sintassi JOIN, quindi è possibile farlo in un'unica istruzione.

Quando interrogazione dei dati, è possibile farlo semplicemente interrogando la tabella media se è necessario solo informazioni sulle colonne comuni:

SELECT name, url FROM media WHERE media_id = ? 

Se si sa che si sta interrogando un film, è possibile ottenere specifici film informazioni con un solo join:

SELECT m.name, v.release_date 
FROM media AS m 
INNER JOIN movies AS v USING (media_id) 
WHERE m.media_id = ? 

Se volete informazioni per una determinata voce di supporto, e non si sa che tipo è, dovresti iscriverti per tutte le tabelle sottotipo, sapendo che solo una tale tabella di sottotipo corrisponderà a:

Se il supporto specificato è un film, tutte le colonne in t.* saranno NULL.

+0

Qualche informazione sul supporto di JDBC? Passerà solo le query e gli aggiornamenti al DBMS, anche se vengono utilizzate annotazioni speciali per i sottotipi? O ci saranno problemi? –

+0

No, è necessario scrivere l'SQL corretto. JDBC fa molto poco rispetto alla riscrittura delle query. Non supporta alcuna annotazione, solo poche sequenze di escape per aiutare la compatibilità del fornitore. –

+0

Quindi il set di risultati avrà solo valori null per gli attributi non utilizzati dai sottotipi correnti? E come leggerà il sottotipo stesso, tramite l'attributo verificato? –

1

È possibile creare una tabella con i campi principali più una tabella di estensione UID quindi con lo stesso UID per ciascun caso specifico. Per interrogare questi come tabelle separate è possibile creare viste.

8

Considerare l'utilizzo di una tabella di dati di base principale con tabelle che si estendono al di fuori di essa con informazioni specializzate.

Es.

basic_data 
id int, 
name character varying(100), 
description text, 
url character varying(255) 


tv_series 
id int, 
BDID int, --foreign key to basic_data 
season, 
episode 
airing 


movies 
id int, 
BDID int, --foreign key to basic_data 
release_data 
budget 
+0

Grazie, ci ho già pensato prima, l'unico problema che ho avuto con questo è che teoricamente dà la possibilità di avere più voci nelle tabelle per uno in basic_data (cioè potrebbe esserci una voce in tv_series e film). Se non arriva niente di meglio, lo faccio in questo modo. –

+0

E anche questa è una relazione unidirezionale poiché solo le tabelle specializzate indicano la tabella generale. –

+0

Voto in aumento, sebbene suggerirei di fare attenzione con la tabella "basic_data" per non renderla troppo generica. Se è "media" o qualcosa del genere ha senso. Non cercare di forzare cose che non hanno senso però. –

2

Quello che stai cercando è chiamato "sottotipi disgiunti" nel mondo relazionale. Non sono supportati in sql a livello di lingua, ma possono essere più o meno implemented on top of sql.

1

Utilizzando l'approccio del sottotipo disgiunto suggerito da Bill Karwin, come faresti INSERT e UPDATE senza doverlo fare in due passaggi?

Ottenendo i dati, posso introdurre una vista che si unisce e seleziona in base al tipo di media specifico ma AFAIK non posso aggiornare o inserire in quella vista perché interessa più tabelle (sto parlando di MS SQL Server qui). Questo può essere fatto senza fare due operazioni - e senza una stored procedure, a livello nativo.

Grazie

+0

Beh, immagino, potrei usare un trigger anziché uno per farlo funzionare, ma significa che dovrei codificarlo per ogni sottotipo che ho. Inoltre, penso che i trigger siano così "segreti" quando si esegue il debug ... Esiste un modo migliore? – Peter

1

domanda è piuttosto vecchio, ma per le versioni moderne PostreSQL è anche la pena di considerare l'uso di tipo JSON/jsonb/hstore. Ad esempio:

create table some_table (
    name character varying(100), 
    description text, 
    url character varying(255), 
    additional_data json 
); 
Problemi correlati