Cómo almacenar estados de registro (como pendiente, completo, borrador, cancelado ...)

18

Muchas aplicaciones requieren registros en sus tablas para tener un estado, como 'completo', 'borrador', 'cancelado'. ¿Cuál es la mejor manera de almacenar estos estados? Para ilustrar lo que estoy llegando aquí es un * muy breve) ejemplo.

Tengo una aplicación de blog simple y cada publicación tiene un estado de: publicado, borrador o pendiente.

A mi modo de ver, hay 2 formas de modelar esto en la base de datos.

  1. La tabla Publicar tiene un campo de texto que incluye el texto de estado.
  2. La tabla Post tiene un campo de estado que contiene el ID de un registro en la tabla PostStatus

El ejemplo del blog aquí es un ejemplo muy simple. Donde una enumeración (si es compatible) podría ser suficiente. Sin embargo, me gustaría que las respuestas a la pregunta tengan en cuenta que la lista de estados podría cambiar en cualquier momento, por lo que se podrían agregar o eliminar más.

¿Alguien puede explicar las ventajas / desventajas de cada uno?

¡Salud!

Mi opinión inicial sobre esto es que es mejor usar otra tabla y buscar el estado, ya que es mejor para la normalización y siempre me han enseñado que la normalización es buena para las bases de datos.

veganista
fuente
¿Qué quieres decir con "en cualquier momento"? ¿Eso significa como parte de la actividad del usuario, o como parte del ciclo de lanzamiento de software?
Kevin Cline
Ambos, en cuyo caso, cualquiera de los enfoques mencionados aquí es mejor utilizado. Entonces, si los usuarios pueden agregar nuevos estados, o si se agregan nuevos en un momento posterior del proyecto
veganista
Almacenar el texto en la base de datos puede ser una buena desnormalización. Creo que puede depender de detalles precisos, por ejemplo, ¿con qué frecuencia su organización cambia sus procesos (lo que lleva a posibles cambios de estado)?
Jaydee
Si los usuarios pueden agregar nuevos estados, entonces es algo completamente diferente. Probablemente querrá registrar el usuario creador, etc. con el estado y definitivamente necesitará otra tabla.
Kevin Cline

Respuestas:

14

Almacenar el estado como un índice en otra tabla es una complicación innecesaria. Almacene el estado directamente en la tabla de forma legible. En el código de la aplicación, use constantes o un tipo de enumeración. Esto dará como resultado un código de aplicación más simple y facilitará la depuración de la capa de datos.

Esto no desnormaliza los datos, simplemente cambia la representación. Si la base de datos admite enumeraciones directamente, úsela. De lo contrario, use una restricción para restringir los valores de columna. Va a tener una restricción de cualquier manera: ya sea una restricción directa en los valores de columna o una restricción de clave externa.

Sí, es posible que deba presentar el estado de manera diferente a los diferentes usuarios. Ese es un problema de presentación, que se resolverá en la capa de presentación, no en la capa de persistencia.

Kevin Cline
fuente
1
+1, salvo una necesidad específica de mantener la lista de estados en la base de datos, esta es generalmente la forma más simple y menos complicada de hacerlo.
Gran maestro
2
Esto está bien, a menos que empezar a cambiar la arquitectura de estado o el almacenamiento de fechas de mutación
LastTribunal
10

Almacenar el texto de estado es IMO, no es una buena idea, ya que alguien podría decidir que "completo" debería llamarse "terminado" y luego debe actualizar su base de datos, mirar a través del programa si alguien codificó el texto, etc.

Lo que he visto en muchos programas es un código numérico (1 = nuevo, 2 = borrador, 3 = en validación, 4 = completo, 99 = cancelado) o un código alfanumérico corto ("NUEVO", "DRA", "INV "," COM "," CAN "). El último hace que el código (en el programa o en la base de datos) sea más legible para los humanos, lo que generalmente es algo bueno. Por otro lado, los códigos numéricos facilitan hacer comparaciones "mayores que" o "menores que", por ejemplo

select * from myrecords where status < Status.Complete;
usuario281377
fuente
Algunos idiotas también pueden usar la identificación.
Morons
Otra ventaja de los ID es que necesita proporcionar localización. Puede usar su ID para buscar la cadena de recursos y mostrarla. Con cadenas codificadas, esto no es posible
Armitage
3
No creo que sea una buena idea hacer estados usando comparaciones "mayor que" o "menor que" como usted ha mostrado. Puede funcionar para aplicaciones más simples como este ejemplo, pero no es bueno para aplicaciones más complejas (aunque estoy seguro de que lo sabe)
veganista
1
@armitage: es perfectamente posible hacer una búsqueda con cadenas. Los nombres de recursos son cadenas:status.draft=Draught
Kevin Cline
veganista: Claro, puede haber dificultades con comparaciones mayores que / menores que, pero he visto sistemas grandes y complejos que hacen eso y viven.
user281377
4

Las tres reglas de las bases de datos relacionales:

  1. Normalizar
  2. Normalizar
  3. Normalizar

Entonces su pregunta se responde sola. Mantenga el estado dentro de su propia tabla y use GUID / UUID como su ID . Los GUID indexados son muy rápidos y solucionan los problemas intrínsecos al incremento de números. Con una identificación, puede hacer cosas interesantes como pedirle a la base de datos todas las publicaciones completadas utilizando la identificación, y debido a que está trabajando dentro del paradigma relacional de db, es muy rápido. Si solo tiene un campo, la base de datos debe recorrer cada fila y hacer una comparación de texto, tal vez con munging, y eso es muy lento.

Los nombres de estado de las publicaciones pueden cambiar, puede encontrar más información sobre el estado de las publicaciones, todo funciona si se normaliza .

Por ejemplo, puede agregar niveles de estado como información adicional, lo que permitiría las menciones de comparación de ammoQ. Pero no dependen de la clave para el posicionamiento, lo que permite reorganizar el nivel de estado sin dañar la integridad de la base de datos. También puede insertar niveles adicionales, lo cual es un buen truco si tiene el nivel asociado a la clave de aumento automático.

Spencer Rathbun
fuente
Las razones que ha indicado aquí son exactamente las razones por las que he estado usando otra tabla para almacenar mis posiciones. La razón principal por la que hice esta pregunta es para ver si a veces es bueno usar un campo de texto más simple.
veganista
@Liam Solo si se normaliza a un campo de texto. Es decir, si su campo de texto depende solo de la clave primaria, y está buscando cosas basadas en la clave primaria , con el campo de texto que aparece. Una base de datos relacional se trata de relaciones, tiene una aquí, por lo que debe definirse. Una de las pocas excepciones es si maneja datos sucios de una fuente externa y no tiene tiempo para modelarlos por completo. Evita esto si es posible.
Spencer Rathbun
oculta los ojos, llorando los GUID que nunca volverán
sq33G
Deberías haber escrito "tres teorías de bases de datos relacionales". La teoría no siempre es práctica. A menudo es más eficiente almacenar un código de estado directamente en el registro con el que está relacionado. Si no necesita buscarlo para usarlo, eliminar la unión a otra tabla ahorra mucho procesamiento desperdiciado.
Suncat2000
Voto negativo debido a la información incorrecta sobre los tipos de columna frente a los escaneos de tabla completa.
igorrs
3

Sí, debe ir con la opción 2, que tiene una tabla PostStatus.

Aparte de todas las ventajas mencionadas en otras respuestas.

Teniendo en cuenta que los estados deben agregarse o eliminarse, puede tener una columna "habilitada" en la tabla PostStatus, por lo que si se elimina el estado marque la columna "habilitada" como "N", de esa manera podrá agregar o eliminar estados y también los registros existentes permanecerán sin problemas.

Mr Spark
fuente
1

Me gustaría agregar a las respuestas perspicaces que para una normalización completa, un cambio en el estado de una entidad se modela en una entidad separada, por ejemplo, llamado 'statusChange'.

Necesitaría una unión adicional con la entidad statusChange, pero tiene la posibilidad de agregar información adicional, como el actor que realiza el cambio, posibles comentarios sobre por qué ocurrió el cambio y una fecha en la que se realiza el statusChange y posiblemente incluso cuando Se vuelve efectivo.

Dibbeke
fuente
0

El uso de texto para el estado en la tabla de registro probablemente no sería una buena idea, ya que esto puede cambiar y sería difícil realizar cualquier verificación de integridad de datos en la inserción / actualización. Si está utilizando un DBMS con un tipo de datos enum, puede usar esto en su lugar (el rendimiento probablemente no se verá comprometido ... dependiendo).

Si su estado necesita algún metadato (descripción, creado por, nombre descriptivo, ...), deberá almacenar los estados en una tabla separada y tener una clave de estado en su tabla de registro (asegúrese de usar una clave externa). La identificación no necesariamente debe ser un número, solo el PK de la tabla de estado. Además, si los estados están en su propia tabla, puede compartirlos entre tipos de registros (tablas) si corresponde. No me preocuparía por problemas de rendimiento con JOIN a la tabla de estado.

Hagas lo que hagas, asegúrate de evitar los estados mágicos (1 para activo, 2 para eliminado, ...). Esto se basa en la documentación y la tradición, que siempre tienden a perderse en una línea de tiempo lo suficientemente grande. Si está utilizando identificadores numéricos, asegúrese de que haya una asociación textual en algún lugar de su base de datos.

smp7d
fuente
Si no te preocupa el rendimiento, es probable que estés sacrificando la escalabilidad. Es imposible para las computadoras evitar estados mágicos: 0 y 1 son intrínsecamente mágicos.
Suncat2000
0

Depende del propósito del diseño de la base de datos.

Si diseña la base de datos simplemente para admitir la aplicación (es decir, los objetos (código) son maestros de todo), entonces usar una enumeración (o una enumeración psuedo para clases que no las admiten) y almacenar el nombre de la enumeración es un buena idea porque aún controla los valores permitidos a través de la enumeración y también hace que la tabla sea un poco más fácil de leer cuando se ve obligado a ver los datos sin procesar (que no es tan frecuente si el código realmente lo gobierna todo). Pero si la enumeración está marcada. Luego, generalmente almaceno el valor de enumeración (entero).

ElGringoGrande
fuente
-1

El estado es muy importante, cada vez que reciba información de la publicación, deberá obtener su estado, o querrá filtrar las publicaciones por estado. Si tiene el estado en otra tabla, deberá hacer uniones para obtener esta información y así el rendimiento se verá comprometido. Definitivamente deberías tener estado en la misma tabla. ¡Y ponle un índice! Todavía puede usar enteros como estado, o tal vez enum field.

dxvargas
fuente
-2

La solución correcta es usar una tienda / fuente de eventos con CQRS o una cadena de bloques. El problema con la captura de eventos en un RDB es que RDB almacena una instantánea de un solo evento en el tiempo, y cosas como "Estados / Estados" son secuencias de mutaciones que evolucionan con el tiempo

Último Tribunal
fuente
Si vas a rechazar votar mi publicación, entonces presenta un caso. De lo contrario, solo eres un lemming de mente suave que tiene muy poco alcance fuera de la caja
LastTribunal