2010-07-22 5 views
6

Sto progettando un gioco in cui un personaggio ha molti oggetti e quegli oggetti possono essere di molti tipi. C'è una tabella dei personaggi e dodici diverse tabelle di possibili elementi suddivisi per tipo (come armi, armature e vari altri tipi di oggetti).Normalizzare questo database: quale sarebbe l'ideale in questo scenario?

Voglio creare una tabella per contenere istanze di questi tipi di elementi (in pratica una tabella di elementi di caratteri) ogni riga avrà una chiave esterna dalla tabella dei caratteri per indicare quale personaggio ha la proprietà di quell'elemento.

All'inizio ho pensato di creare delle chiavi esterne nella tabella degli oggetti dei personaggi - una chiave per ciascuna delle dodici tabelle degli articoli. Ma dal momento che ogni elemento può essere di un solo "tipo", questo porterebbe a undici campi null in ogni riga e ciò sembra sbagliato.

Quale sarebbe l'approccio migliore? Devo ancora creare il database, così posso intrattenere altre idee di inventario che non usano dodici tabelle di articoli, ma so questo: l'interfaccia di amministrazione consentirà a un utente di aggiungere/rimuovere/modificare gli elementi di ciascun tipo secondo necessità.

Inoltre, mi piacerebbe attenermi alla migliore pratica di normalizzazione, quindi ignorerò l'inevitabile "A chi importa? Basta fare ciò che funziona e utilizzare campi null-capaci".

+1

La migliore pratica di normalizzazione non è sempre la migliore pratica di programmazione. In particolare, tutto ciò che richiederebbe l'interrogazione di 12 tabelle quando è possibile garantire che restituirai solo le righe da 1 di esse non è la migliore prassi di programmazione, indipendentemente da quanto compatto e non ridondante sia il tuo set di dati. Quali sono le tue priorità per questo sistema? – Kylotan

+0

@Kylotan +1 - la normalizzazione dovrebbe sempre essere applicata, ma è un atto di bilanciamento, in teoria è possibile normalizzare fino all'ennesima potenza, ma a questo punto si avranno molte tabelle, rallentando le prestazioni della query. – Dal

risposta

3

Prima vorrei verificare se è possibile unificare questi dodici tavoli in uno solo. Inizia con Single-Table Inheritance, perché è semplice e scommetto che sarebbe adeguato in questo caso.

CHARACTER --<- CHAR_ITEMS ->-- ITEM_TYPES_STI 

In caso contrario, prova Class Table Inheritance. Fondamentalmente, definisci un superabile per "tipo di oggetto" e gli elementi del personaggio fanno riferimento a questo. Ogni sotto-tavolo per i 12 tipi di elementi di riferimento individuali anche i tipi di elementi supertable:

CHARACTER --<- CHAR_ITEMS ->-- ITEM_TYPES_SUPER --- ITEM_TYPE_SWORDS 

Re tuo commento: Ho chiarito la linea di cui sopra. La relazione tra item_types_super e item_type_swords dovrebbe essere 1: 1. Cioè, per ogni fila di spade ci dovrebbe essere una riga distinta in super. Il modo per farlo è rendere la chiave estranea nelle spade anche la sua chiave primaria.

Ma non tutte le file in super hanno una fila in spade. La riga in super può essere referenziata da una riga in scudo, o assi, o qualsiasi altra cosa. Ma solo per un sottotipo. L'idea è che le colonne comuni a tutti i tipi di oggetto appartengano in super, e le colonne che sono specifiche per sottotipo vanno in ogni sottotipo.

+0

Se capisco il tuo secondo esempio: un personaggio ha molti char_items, un item_type_super ha molti char_items e item_type_swords. Se l'amministratore inserisce alcune spade nella tabella item_type_swords e una riga nella tabella char_items ha una chiave che si associa a un tipo "spada" nella tabella item_types_super, come posso sapere quale spada della tabella item_type_swords è destinata a essere? – Stephen

+0

Grazie, corro con esso e vedo cosa succede! – Stephen

1

Se si sono utilizzate le seguenti tabelle (ho incluso solo i valori chiave per le colonne). La tabella CHARACTERS_ITEMS contiene l'elenco di elementi per ciascun carattere. La combinazione di ItemTypeID e ItemID verrebbe utilizzata per fare riferimento a una riga in una delle 12 tabelle di articoli.

CHARACTERS 
---------- 
CharacterID (PK) 

ITEMS 
----- 
ItemID (PK) 

ITEM_TYPES 
---------- 
ItemTypeID (PK) 

CHARACTERS_ITEMS 
---------------- 
CharacterID (FK) 
ItemTypeID (FK) 
ItemID (FK) 

Ecco l'inizio di una vista che può essere utile pure. Dimostra come è possibile utilizzare ItemTypeId per fare riferimento alla tabella appropriata.

CREATE VIEW v_character_items 
AS 
SELECT {list of columns} 
FROM character_items 
JOIN character_item_1 on character_items.ItemID = character_item_1.ItemID and character_items.ItemTypeID = 1 

UNION 
SELECT {list of columns} 
FROM character_items 
JOIN character_item_2 ON character_items.ItemID = character_item_2.ItemID and character_items.ItemTypeID = 2 

UNION 
{other tables...} 
+0

Sto rivedendo il tuo progetto per vedere se funziona per me, ma devo dire: perché usare 'UNION'? Credo che dovresti studiare l'apprendimento delle sintassi di 'JOIN'. – Stephen

+0

Grazie a @Stephen. Sono sicuro che ho molto da imparare da te. Non sapevo che potessi fare JOINs in SQL. Supponi di voler visualizzare le seguenti colonne character_items.CharacterID, character_items.ItemId e le colonne della tabella character_item_1, character_item_2, ecc. puoi mostrarmi quale sarebbe la clausola SELECT se sostituissi UNIONs con JOINS? – bobs

+0

'SELECT character_items.CharacterID, character_items.ItemId, character_item_1. *, Character_item_2. * FROM character_items JOIN character_item_1 ON character_items.ItemID = character_item_1.ItemID JOIN character_item_2 ON character_items.ItemID = character_item_2.ItemID;' – Stephen

1

Nel tuo caso, proverei a unire tutte e dodici le tabelle in un unico tavolo.

La ragione di questo non è in realtà nulla a che fare con il disegno tecnico del tavolo - ma piuttosto permetterà ai tuoi personaggi di riutilizzare gli oggetti in modi inaspettati.

Si potrebbe ad esempio avere una serie di attributi lanciabili come EFFORT, PRECISIONE, DANNO, ROTTURA in modo che un pugnale non sia quasi nessuno sforzo da lanciare e causare una grande quantità di ferita se ha bloccato il bersaglio, dall'altro Tenere a portata di mano un calice sarebbe facile da lanciare ma causare un danno molto piccolo o una barra d'oro sarebbe difficile da lanciare ma potrebbe causare una quantità ragionevole di danno anche se non si tratta di un'arma. Permetterebbe anche di avere armi che erano anche oggetti "preziosi" di grande valore o uso magico (non so che tipo di gioco stai pianificando, quindi questi esempi potrebbero non essere appropriati

+0

+1 per un'idea interessante. – Stephen

1

Non so se tu 're ancora alla ricerca di risposte, ma ecco come ho fatto il mio poco tempo fa:.

CHARACTER -> Char/Item Link Table -> ITEM 

ITEM 
---- 
ID 
NAME 
TYPE 
etc. 

questo ti permette di creare oggetti di base che più personaggi possono possedere se si vuole fare modifiche di carattere individuale di oggetti (ad esempio gemma slotting, incantesimi, ecc.) che possono essere fatti facilmente attraverso una tabella EFFECT (o qualcosa di simile):

ITEM -> Item/Effect Link Table -> EFFECTS 

In questo modo è possibile avere caratteri che personalizzano le proprie armi e mantengono comunque la base. Puoi anche creare una serie di effetti senza doverli ripetere più volte per ogni oggetto del gioco.