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


18

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

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

Per come la vedo io ci sono 2 modi per modellarlo nel database.

  1. La tabella Posta ha un campo di testo che include il testo dello stato.
  2. La tabella Post ha un campo di stato che contiene l'ID di un record nella tabella PostStatus

L'esempio Blog qui è un esempio molto semplice. Dove un enum (se supportato) potrebbe essere sufficiente. Tuttavia, vorrei che le risposte alla domanda prendessero in considerazione il fatto che l'elenco degli stati potrebbe cambiare in qualsiasi momento, in modo da poterne aggiungere o rimuovere altri.

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

Saluti!

La mia scelta iniziale è 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



Cosa intendi con "in qualsiasi momento"? Significa come parte dell'attività dell'utente o come parte del ciclo di rilascio del software?
Kevin Cline,

Entrambi, in quali casi sono meglio utilizzati gli approcci citati qui. Quindi, se gli utenti sono in grado di aggiungere nuovi stati o se ne vengono aggiunti di nuovi in ​​un momento successivo del progetto
veganista,

La memorizzazione del testo nel database può essere una buona denormalizzazione. Penso che possa dipendere da dettagli precisi, ad es. Con quale frequenza l'organizzazione cambia i suoi processi (portando a possibili cambiamenti di stato)?
Jaydee,

Se gli utenti sono in grado di aggiungere nuovi stati, allora è completamente un'altra cosa. Probabilmente vorrai registrare l'utente che crea ecc. Con lo stato e avrai sicuramente bisogno di un'altra tabella.
Kevin Cline,

Risposte:


14

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 costanti o un tipo di enumerazione. Ciò comporterà un codice applicazione più semplice e faciliterà il debug del livello dati.

Questo non denormalizza i dati, cambia semplicemente la rappresentazione. Se il database supporta direttamente le enumerazioni, utilizzarlo. In caso contrario, utilizzare un vincolo per limitare i valori della colonna. Avrai un vincolo in entrambi i casi: un vincolo diretto sui valori di 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.


1
+1, salvo una specifica necessità di mantenere l'elenco degli stati nel db, questo è generalmente il modo più semplice e meno complicato per farlo.
GrandmasterB,

2
Va

10

La memorizzazione del testo di stato non è una buona idea dell'IMO, dal momento che qualcuno potrebbe decidere che "completo" dovrebbe essere chiamato "finito" invece e quindi è necessario aggiornare il database, esaminare 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 convalida, 4 = completo, 99 = annullato) o un breve codice alfanumerico ("NUOVO", "DRA", "INV "," COM "," CAN "). Il successivo rende il codice (nel programma o nel database) più leggibile dall'uomo, il che è generalmente una buona cosa. D'altra parte, i codici numerici rendono facile fare confronti "maggiori di" o "minori di", ad esempio

select * from myrecords where status < Status.Complete;

Alcuni idioti possono anche identificare l'ID.
Morons,

Un altro vantaggio degli ID è che è necessario fornire la localizzazione. È possibile utilizzare il proprio ID per cercare la stringa di risorse e visualizzarla. Con stringhe hard coded questo non è possibile
armitage

3
Non penso che fare degli stati usando confronti "maggiore di" o "minore di" come hai mostrato sia una buona idea. Può funzionare per applicazioni più semplici come questo esempio, ma non va bene per le app più complesse (anche se sono sicuro che tu ne sia consapevole)
Veganista,

1
@armitage: è perfettamente possibile effettuare una ricerca utilizzando le stringhe. I nomi delle risorse sono stringhe:status.draft=Draught
kevin cline,

veganista: Certo, ci possono essere difficoltà con un confronto maggiore o minore rispetto ai confronti, ma ho visto sistemi grandi e complessi che lo fanno e vivono.
user281377,

4

Le tre regole dei database relazionali:

  1. Normalizzare
  2. Normalizzare
  3. Normalizzare

Quindi la tua domanda risponde a se stessa. Mantenere lo stato all'interno della propria tabella e utilizzare 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 poiché stai lavorando all'interno del paradigma db relazionale, è molto veloce. Se hai solo un campo, il DB deve scorrere su ogni singola riga e fare un confronto testuale, magari con il munging, e questo è molto lento.

I nomi dello stato dei post possono cambiare, più informazioni sullo stato dei post possono andare nella tabella, tutto funziona solo se si normalizza .

Ad esempio, è possibile aggiungere livelli di stato come informazioni aggiuntive, il che consentirebbe le menzioni di confronto di munizioni. Ma non dipendono dalla chiave per il posizionamento, consentendo di riorganizzare il livello di stato senza danneggiare l'integrità del DB. Puoi anche inserire livelli aggiuntivi, il che è piuttosto un trucco se hai il livello associato alla chiave di incremento automatico.


Le ragioni che hai indicato qui sono esattamente le ragioni per cui sto usando un altro tavolo per conservare le mie scuderie. Il motivo principale per cui ho posto questa domanda è vedere se a volte è utile usare un campo di testo più semplice.
Veganista,

@Liam Solo se si normalizza in un campo di testo. Cioè, se il tuo campo di testo dipende solo dalla chiave primaria e stai osservando le cose in base alla chiave primaria , con il campo di testo in arrivo. Un DB relazionale riguarda le relazioni, ne hai uno qui, quindi deve essere definito. Una delle poche eccezioni è se stai gestendo dati sporchi da una fonte esterna e non hai il tempo di modellarli completamente. Evitatelo se possibile.
Spencer Rathbun,

nasconde gli occhi, in lutto per i GUID che non torneranno mai più
sq33G,

Avresti dovuto scrivere "tre teorie sui database relazionali". La teoria non è sempre pratica. Spesso è più efficiente memorizzare un codice di stato direttamente nel record a cui è correlato. Se non è necessario cercarlo per utilizzarlo, la rimozione del join su un'altra tabella consente di risparmiare un sacco di sprechi.
Suncat2000,

Sottovalutato a causa di informazioni errate sui tipi di colonna rispetto alle scansioni di tabelle complete.
igorrs,

3

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

A parte tutti i vantaggi menzionati in altre risposte.

Tenendo presente che è necessario aggiungere o rimuovere gli stati, è possibile avere una colonna "abilitata" nella tabella PostStatus, quindi se lo stato viene rimosso contrassegnare la colonna "abilitata" come "N", in questo modo sarà possibile aggiungere o rimuovere stati e anche i record esistenti rimarranno senza problemi.


1

Vorrei aggiungere alle risposte altrimenti approfondite che per la piena normalizzazione, un cambiamento nello stato di un'entità è in realtà modellato in un'entità separata, ad esempio denominato "statusChange".

Avresti bisogno di un ulteriore join con l'entità statusChange, ma vinci la possibilità di aggiungere ulteriori informazioni, come l'attore che esegue la modifica, i possibili commenti sul perché si è verificata la modifica e una data in cui viene eseguito lo statusChange e possibilmente anche quando diventa efficace.


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 qualsiasi controllo di integrità dei dati su insert / update. Se stai utilizzando un DBMS con un tipo di dati enum, puoi invece usarlo (le prestazioni probabilmente non saranno compromesse ... a seconda).

Se il tuo stato richiede metadati (descrizione, creato da, nome descrittivo, ...) dovrai archiviare gli stati in una tabella separata e avere una chiave di stato nella tabella dei record (assicurati di utilizzare una chiave esterna). L'id non deve necessariamente essere un numero, ma solo il PK della tabella di stato. Inoltre, se gli stati sono nella propria tabella, è possibile condividerli tra tipi di record (tabelle), se applicabile. Non mi preoccuperei dei problemi di prestazioni con un JOIN nella 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 hanno sempre la tendenza a perdersi su una linea temporale abbastanza ampia. Se stai usando gli ID numerici, assicurati che ci sia un'associazione testuale da qualche parte nel tuo db.


Se non ti preoccupi delle prestazioni, probabilmente stai sacrificando la scalabilità. È impossibile per i computer evitare gli stati magici: 0 e 1 sono intrinsecamente magici.
Suncat2000,

0

Dipende dallo scopo della progettazione del database.

Se si progetta il database semplicemente per supportare l'applicazione (vale a dire che gli oggetti (codice) sono padrone di tutti), utilizzare un'enumerazione (o un'enumerazione psuedo per le classi che non li supportano) e archiviare il nome dell'enum è un buona idea perché controlli ancora i valori consentiti attraverso l'enum e rendi anche la lettura della tabella un po 'più semplice quando sei costretto a visualizzare i dati grezzi (che non è così frequente se il codice governa effettivamente tutto). Ma se l'enumerazione è contrassegnata. Quindi di solito memorizzo il valore enum (numero intero).


-1

Lo stato è molto importante, ogni volta che ricevi informazioni sui post dovrai ottenerne lo stato o vorrai filtrare i post per stato. Se hai lo stato in un'altra tabella, dovrai ottenere unioni per ottenere queste informazioni e quindi le prestazioni sono compromesse. Sicuramente dovresti avere lo stato nella stessa tabella. E mettici sopra un indice! Puoi ancora usare numeri interi come stato, o forse campo enum.


-2

La soluzione corretta è utilizzare un archivio / 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


Se hai intenzione di votare in basso il mio post, allora fai un caso. Altrimenti sei solo un lemming dalla mente leggera che ha ben poco spazio fuori dagli schemi
LastTribunal
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.