database design - español - ¿Cuál es la mejor manera de almacenar los días de la semana en que ocurre un evento en una base de datos relacional?
crear aplicaciones con powerapps (6)
Estamos escribiendo un producto de administración de registros para las escuelas y uno de los requisitos es la capacidad de administrar los horarios de los cursos. No he visto el código de cómo lidiamos con esto (estoy en un proyecto diferente en este momento), pero empecé a preguntarme cómo manejar mejor una parte particular de este requisito, a saber, cómo manejar el hecho de que cada curso se puede llevar a cabo uno o más días de la semana, y la mejor manera de almacenar esta información en la base de datos. Para proporcionar un contexto, una tabla de Course
básicos puede contener las siguientes columnas:
Course Example Data
------ ------------
DeptPrefix ;MATH, ENG, CS, ...
Number ;101, 300, 450, ...
Title ;Algebra, Shakespeare, Advanced Data Structures, ...
Description ;...
DaysOfWeek ;Monday, Tuesday-Thursday, ...
StartTime
EndTime
Lo que me pregunto es, ¿cuál es la mejor manera de manejar la columna DaysOfWeek
en este ejemplo (artificial)? El problema que estoy teniendo es que se trata de un campo multivaluado: es decir, puede tener un curso en cualquier día de la semana y el mismo curso puede tomarse en más de un día. Sé que ciertas bases de datos admiten columnas de valores múltiples de forma nativa, pero ¿existe una "mejor práctica" para manejar esto suponiendo que la base de datos no lo admite de forma nativa?
Hasta ahora he llegado a las siguientes soluciones posibles, pero me pregunto si alguien tiene algo mejor:
Posible solución n. ° 1: trate DaysOfWeek como un campo de bit
Esto fue lo primero que me vino a la cabeza (no estoy seguro de si eso es algo bueno o no ...). En esta solución, DaysOfWeek
se definiría como un byte, y los primeros 7 bits se usarían para representar los días de la semana (un bit por cada día). Un 1 bit indicaría que se realizó una clase el día correspondiente de la semana.
Pros : Fácil de implementar (la aplicación puede manejar las manipulaciones de bit), funciona con cualquier base de datos.
Contras : es más difícil escribir consultas que utilizan la columna DaysOfWeek
(aunque podría tratar esto a nivel de aplicación, o crear vistas y procedimientos almacenados en la base de datos para simplificar esto), rompe el modelo de base de datos relacional.
Posible solución n. ° 2: almacene DaysOfWeek como una cadena de caracteres
Este es esencialmente el mismo enfoque que usar un campo de bit, pero en lugar de tratar con bits crudos, asigna una letra única a cada día de la semana, y la columna DaysOfWeek
solo almacena una secuencia de letras que indica en qué días se lleva a cabo un curso . Por ejemplo, puede asociar cada día de la semana con un código de un solo carácter de la siguiente manera:
Weekday Letter
------- ------
Sunday S
Monday M
Tuesday T
Wednesday W
Thursday R
Friday F
Saturday U
En este caso, un curso celebrado los lunes, martes y viernes tendría el valor ''MTF''
para DaysOfWeek
, mientras que una clase que se celebrará únicamente los miércoles tendría un valor de DaysOfWeek
de ''W''
.
Pros : es más fácil de tratar en consultas (es decir, puede usar INSTR
o su equivalente para determinar si una clase se lleva a cabo en un día determinado). Funciona con cualquier base de datos que admita INSTR o una función equivalente (la mayoría, supongo ...). También es más fácil de ver y fácil de ver de un vistazo qué está sucediendo en las consultas que usan la columna DaysOfWeek
.
Contras : El único "contra" real es que, al igual que el enfoque de campo de bits, esto rompe el modelo relacional almacenando un número variable de valores en un solo campo.
Posible solución n. ° 3: utilice una tabla de búsqueda (fea)
Otra posibilidad sería crear una nueva tabla que almacene todas las combinaciones únicas de días de la semana, y hacer que la columna Course.DaysOfWeek
simplemente sea una clave externa en esta tabla de búsqueda. Sin embargo, esta solución parece ser la menos elegante, y solo la consideré porque parecía que The Relational Way TM podía hacer cosas.
Pros : es la única solución que es "pura" desde el punto de vista de una base de datos relacional.
Contras : es poco elegante y engorroso. Por ejemplo, ¿cómo diseñaría la interfaz de usuario para asignar los días de la semana correspondientes a un curso determinado alrededor de la tabla de búsqueda? Dudo que un usuario quiera lidiar con opciones como "domingo", "domingo, lunes", "domingo, lunes, martes", "domingo, lunes, martes, miércoles", y así sucesivamente ...
¿Otras ideas?
Entonces, ¿hay una forma más elegante de manejar valores múltiples en una sola columna? ¿O serían suficientes las soluciones propuestas? Por lo que vale, creo que mi segunda solución es probablemente la mejor de las tres posibles soluciones que describí aquí, pero me gustaría saber si alguien tiene una opinión diferente (o incluso un enfoque diferente).
Evitaría la opción de cadena para la sensación de pureza: agrega una capa adicional de codificación / decodificación que no necesita. También puede arruinarlo en el caso de la internacionalización.
Como la cantidad de días en una semana es 7, mantendría siete columnas, quizás booleanas. Esto también facilitará consultas posteriores. Esto también será útil si la herramienta se utiliza alguna vez en países donde la semana laboral comienza en días diferentes.
Evitaría la búsqueda porque sería una sobrenormalización. A menos que su conjunto de elementos de búsqueda no sea obvio o pueda cambiar, es exagerado. En el caso de los días de la semana (a diferencia de los estados de EE. UU., Por ejemplo), dormía profundamente con el aparato fijo.
Teniendo en cuenta el dominio de los datos, no creo que un campo de bits logre ningún ahorro significativo de espacio para usted y simplemente haría su código más complejo.
Finalmente, una palabra de advertencia sobre el dominio: muchas escuelas hacen cosas raras con sus horarios donde "intercambian días" para equilibrar un número igual de días de la semana de cada tipo durante el semestre a pesar de las vacaciones. No tengo claro su sistema, pero quizás el mejor enfoque sería almacenar una tabla de las fechas reales en las que se espera que el curso tenga lugar. De esta forma, si hay dos martes en una semana, el maestro puede recibir pago por aparecer dos veces, y el maestro por el jueves cancelado no pagará.
La solución número 3 parece ser la más cercana a lo que recomendaría. Una extensión sobre la idea de la tabla de búsqueda. Cada curso tiene una o más sesiones. Cree una tabla de sesión con atributos: course_id, day, time, lecturer_id, room_id, etc.
Ahora puede asignar un conferenciante o sala diferente a cada sesión de cada curso, suponiendo que desee almacenar estos datos más adelante.
Los problemas de la interfaz de usuario no son relevantes si está considerando el mejor diseño de base de datos. Siempre puede crear vistas para mostrar los datos, y para capturar los datos su aplicación puede encargarse de la lógica de capturar muchas sesiones para cada curso y agregarlas a la base de datos.
El significado de las tablas sería más claro, lo que facilita el mantenimiento a largo plazo.
No creo que sea difícil escribir consultas si usamos la opción de bit. Solo usa matemática binaria simple. Creo que es el método más eficiente. Personalmente, lo hago todo el tiempo. Echar un vistazo:
sun=1, mon=2, tue=4, wed=8, thu=16, fri=32, sat=64.
Ahora, digamos que el curso se lleva a cabo el lunes, miércoles y viernes. el valor para guardar en la base de datos sería 42 (2 + 8 + 32). Entonces puedes seleccionar cursos en miércoles así:
select * from courses where (days & 8) > 0
si quieres cursos el Jueves y Viernes, deberías escribir:
select * from courses where (days & 48) > 0
este artículo es relevante: http://en.wikipedia.org/wiki/Bitwise_operation
puede poner números de días de semanas, como constantes en su código y será lo suficientemente claro.
Espero eso ayude.
Si el rendimiento es un problema, recomendaría una clasificación más limpia de # 3.
Vincula tu curso a una tabla de "cronograma".
Que a su vez está vinculado a una tabla days_in_schedule.
La tabla days_in_schedule tiene columnas schedule_name y date in_schedule_day. Con una fila para cada día válido en ese horario.
Necesitas un poco de tiempo para usar un programa inteligente para completar la tabla, pero una vez hecho esto, la flexibilidad vale la pena.
Puede hacer frente no solo a "cursos los viernes solamente", sino también a "primer semestre solamente", "laboratorio cerrado para restauración en el tercer semestre" y "sucursal canadiense tiene un horario de vacaciones diferente".
Otras posibles consultas son "¿Cuál es la fecha de finalización del curso de 20 días que comienza el 1 de abril?", Que "programa más choca". Si eres realmente bueno en SQL, puedes preguntar "qué días posibles están abiertos en el curso xxx a un estudiante que ya está reservado para el curso yyy", lo cual tengo la sensación de que es la verdadera fuente de tu sistema propuesto.
Si elige uno o dos, su tabla no estará en 1NF (primera forma normal) ya que contiene una columna de valores múltiples.
Nicholas tiene una idea excelente, aunque estoy en desacuerdo con que su idea rompa la primera forma normal: los datos no se repiten realmente, ya que cada día se almacena de forma independiente. El único problema es que tienes que recuperar más columnas.
Un posible # 4: ¿Por qué necesita ser una sola columna? Puede agregar columnas de 7 bits para cada día de la semana a la mesa. Escribir SQL en contra de esto es simple, solo prueba un 1 en la columna de tu elección. Y la lectura del código de la aplicación de la base de datos solo oculta esto en un interruptor. Me doy cuenta de que esta no es la forma normal y normalmente paso bastante tiempo tratando de deshacer esos diseños de los programadores anteriores, pero dudo un poco que agreguemos un octavo día a la semana en el corto plazo.
Para comentar sobre las otras soluciones, probablemente gemiría si encontré la tabla de búsqueda. Mi primera inclinación también fue el campo de bits con algunas funciones de base de datos personalizadas para ayudarte a escribir consultas naturales contra ese campo fácilmente.
Tendré curiosidad por leer algunas de las otras sugerencias que las personas presentan.
Editar: Debo agregar que # 3 y la sugerencia anterior son más fáciles de agregar índices. No estoy seguro de cómo se podría escribir una consulta SQL como "consígame todas las clases el jueves" para las consultas n.º 1 o n.º 2 que no darían como resultado una exploración de tabla. Pero tal vez solo esté débil esta noche.