Come memorizzare gli stati dei record (come in sospeso, completo, bozza, annullato ...)

14

Molte applicazioni richiedono che i record nelle loro tabelle abbiano uno stato, come "completo", "bozza", "annullato". Qual è il modo migliore per archiviare questi stati? Per illustrare quello che sto ottenendo qui è un * molto breve esempio.

Ho una semplice applicazione Blog e ogni post ha uno stato di: pubblicato, bozza o in sospeso.

Il modo in cui lo vedo ci sono 2 modi per modellarlo nel database.

  1. La tabella dei post contiene un campo di testo che include il testo di stato.
  2. La tabella dei post contiene un campo di stato che contiene l'ID di un record nella tabella PostStatus

L'esempio del blog qui è un esempio molto semplice. Dove un enum (se supportato) potrebbe essere sufficiente. Tuttavia, mi piacerebbe che le risposte alla domanda tengano conto del fatto che l'elenco degli stati potrebbe cambiare in qualsiasi momento, quindi è possibile aggiungerne o rimuoverne altri.

Qualcuno può spiegare i vantaggi / gli svantaggi di ciascuno?

Cheers!

La mia opinione iniziale su questo è che è meglio usare un'altra tabella e cercare lo stato come migliore per la normalizzazione e mi è sempre stato insegnato che la normalizzazione è buona per i database

    
posta veganista 14.02.2012 - 15:10
fonte

9 risposte

13

Memorizzare lo stato come indice in un'altra tabella è una complicazione inutile. Memorizza lo stato direttamente nella tabella in modo leggibile. Nel codice dell'applicazione utilizzare le costanti o un tipo di enumerazione. Ciò comporterà un codice applicativo più semplice e faciliterà il debug del livello dati.

Ciò non denormalizza i dati, ma modifica semplicemente la rappresentazione. Se il database supporta direttamente le enumerazioni, usalo. Altrimenti usa un vincolo per limitare i valori della colonna. Avrai un vincolo in entrambi i casi: un vincolo diretto sui valori della colonna o un vincolo di chiave esterna.

Sì, potrebbe essere necessario presentare lo stato in modo diverso a utenti diversi. Questo è un problema di presentazione, da risolvere nel livello di presentazione, non nel livello di persistenza.

    
risposta data 14.02.2012 - 19:40
fonte
7

Memorizzare il testo di stato è IMO non una buona idea, dal momento che qualcuno potrebbe decidere che "completo" dovrebbe essere chiamato "finito" e poi devi aggiornare il tuo database, guardare attraverso il programma se qualcuno ha codificato il testo ecc.

Quello che ho visto in molti programmi è un codice numerico (1 = nuovo, 2 = bozza, 3 = in validazione, 4 = completo, 99 = annullato) o un breve codice alfanumerico ("NUOVO", "DRA" , "INV", "COM", "CAN"). Più tardi rende il codice (nel programma o nel database) più leggibile dall'uomo, che generalmente è una buona cosa. D'altra parte, i codici numerici facilitano il confronto "maggiore di" o "minore di", ad esempio

select * from myrecords where status < Status.Complete;
    
risposta data 14.02.2012 - 15:19
fonte
4

Le tre regole dei database relazionali:

  1. Normalizza
  2. Normalizza
  3. Normalizza

Quindi la tua domanda risponde da sola. Mantieni lo stato all'interno della propria tabella e usa GUID / UUID come id . I GUID indicizzati sono molto veloci e risolvono i problemi intrinseci all'aumento dei numeri. Con un id puoi fare cose interessanti come chiedere al DB tutti i post completati usando l'id, e dato che stai lavorando all'interno del paradigma relazionale db, è molto veloce. Se hai solo un campo, il DB deve eseguire il loop su ogni singola riga e fare un confronto di testo, magari con il munging, e questo è molto lento.

I nomi degli stati dei post possono cambiare, più informazioni sullo stato dei post possono essere inserite nella tabella, tutto funziona solo se si normalizza .

Ad esempio, puoi aggiungere livelli di stato come informazioni aggiuntive, il che consentirebbe di menzionare ammoQ di confronto. Ma non dipendono dalla chiave per il posizionamento, consentendo la riorganizzazione del livello di stato senza danneggiare l'integrità del DB. Puoi anche inserire livelli aggiuntivi, il che è piuttosto complicato se hai il livello associato alla chiave autoincrementante.

    
risposta data 14.02.2012 - 16:37
fonte
2

Sì, dovresti andare con l'opzione 2, con una tabella PostStatus.

Oltre a tutti i vantaggi menzionati in altre risposte.

Tenendo presente che gli stati devono essere aggiunti o rimossi, è possibile avere una colonna "abilitata" nella tabella PostStatus, quindi se lo stato viene rimosso, contrassegnare la colonna "enabled" come "N", in questo modo si essere in grado di aggiungere o rimuovere stati e anche i record esistenti rimarranno senza problemi.

    
risposta data 15.02.2012 - 09:34
fonte
1

Vorrei aggiungere alle risposte altrimenti perspicaci che per la completa normalizzazione, una modifica dello stato di un'entità viene in realtà modellata in un'entità separata, ad es. chiamato 'statusChange'.

Avresti bisogno di un join aggiuntivo con l'entità statusChange, ma hai la possibilità di aggiungere informazioni extra, come l'attore che sta eseguendo la modifica, eventuali commenti sul perché si è verificata la modifica e una data in cui viene eseguito lo statusChange e forse anche quando diventa efficace.

    
risposta data 14.02.2012 - 18:42
fonte
0

L'uso del testo per lo stato nella tabella dei record non sarebbe probabilmente una buona idea in quanto ciò può cambiare e sarebbe difficile eseguire controlli di integrità dei dati su insert / update. Se si utilizza un DBMS con un tipo di dati enum, è possibile utilizzarlo (le prestazioni probabilmente non saranno compromesse ... a seconda).

Se il tuo stato necessita di qualsiasi metadata (descrizione, creato da, nome descrittivo, ...) sarà necessario memorizzare gli stati in una tabella separata e avere una chiave di stato nella tabella dei record (assicurarsi di utilizzare una chiave esterna) . L'id non deve necessariamente essere un numero, solo il PK della tabella di stato. Inoltre, se gli stati sono nella propria tabella, è possibile condividerli tra i tipi di record (tabelle), se applicabile. Non mi preoccuperei dei problemi di prestazioni con un JOIN alla tabella di stato.

Qualunque cosa tu faccia, assicurati di evitare gli stati magici (1 per attivo, 2 per cancellato, ...). Ciò si basa su documentazione e tradizione che tendono sempre a perdersi su una tempistica abbastanza ampia. Se stai usando id numerici, assicurati che ci sia un'associazione testuale da qualche parte nel tuo db.

    
risposta data 14.02.2012 - 16:03
fonte
0

Dipende dallo scopo della progettazione del database.

Se si progetta il database semplicemente per supportare l'applicazione (cioè gli oggetti (codice) sono padroni di tutti) quindi si utilizza un'enumerazione (o un'enumerazione psuedo per le classi che non li supportano) e si memorizza il nome del enum è una buona idea perché controlli ancora i valori consentiti dall'enumerazione e rendi la tabella più facile da leggere quando sei obbligato a visualizzare i dati non elaborati (che non è così frequente se il codice in realtà domina tutti). Ma se l'enumerazione è contrassegnata. Quindi di solito memorizzo il valore enum (intero).

    
risposta data 14.02.2012 - 20:44
fonte
-1

Lo stato è molto importante, ogni volta che ricevi informazioni sui post devi ottenere il suo stato, o ti consigliamo di filtrare i post in base allo stato. Se si dispone di uno stato in un'altra tabella, è necessario creare join per ottenere queste informazioni e quindi le prestazioni sono compromesse. Sicuramente dovresti avere lo status nella stessa tabella. E mettici un indice! Puoi ancora usare gli interi come stato, o forse enum field.

    
risposta data 14.02.2012 - 15:27
fonte
-2

La soluzione corretta è utilizzare uno Store / sorgente di eventi con CQRS o una blockchain. Il problema con l'acquisizione di eventi in un RDB è che RDB memorizza un'istantanea di un singolo evento nel tempo e cose come "Stati / stati" sono sequenze di mutazioni che si evolvono nel tempo

    
risposta data 06.04.2018 - 20:45
fonte

Leggi altre domande sui tag