una - recorrer tabla sql server cursor
Indicadores en filas de una base de datos, mejores prácticas (7)
En general, evito los campos de máscara de bits. Son difíciles de leer en el futuro y requieren un conocimiento mucho más profundo de los datos para su comprensión.
La solución relacional ha sido propuesta previamente. Dado el ejemplo que describió, crearía algo como esto (en SQL Server):
CREATE TABLE Users (
UserId INT IDENTITY(1, 1) PRIMARY KEY,
FirstName VARCHAR(50),
LastName VARCHAR(50),
EmailAddress VARCHAR(255)
);
CREATE TABLE Badges (
BadgeId INT IDENTITY(1, 1) PRIMARY KEY,
[Name] VARCHAR(50),
[Description] VARCHAR(255)
);
CREATE TABLE UserBadges (
UserId INT REFERENCES Users(UserId),
BadgeId INT REFERENCES Badges(BadgeId)
);
Estoy pidiendo esto por curiosidad. Básicamente mi pregunta es cuando tienes una base de datos que necesita una entrada de fila para tener cosas que actúen como banderas, ¿cuál es la mejor práctica? Un buen ejemplo de esto serían las insignias en el desbordamiento de la pila, o el campo del sistema operativo en bugzilla. Cualquier subconjunto de los indicadores se puede establecer para una entrada determinada.
Por lo general, trabajo c y c ++, así que mi reacción visceral es utilizar un campo entero sin signo como un conjunto de bits que se pueden voltear ... Pero sé que no es una buena solución por varias razones. El más obvio de los cuales es la capacidad de escala, habrá un límite superior difícil en la cantidad de banderas que puedo tener.
También puedo pensar en un par de otras soluciones que escalan mejor pero que tendrían problemas de rendimiento porque requerirían selecciones múltiples para obtener toda la información.
Entonces, ¿cuál es la forma "correcta" de hacer esto?
En muchos casos, depende de muchas cosas, como el back-end de su base de datos. Si está utilizando MySQL, por ejemplo, el tipo de datos SET es exactamente lo que quiere.
Básicamente, es solo una máscara de bits, con valores asignados a cada bit. MySQL admite valores de hasta 64 bits (es decir, 64 conmutadores diferentes). Si solo necesitas 8, solo se necesita un byte por fila, lo cual es un ahorro increíble.
Si honestamente tiene más de 64 valores en un solo campo, su campo puede ser cada vez más complicado. Es posible que desee expandir luego al tipo de datos BLOB, que es simplemente un conjunto de bits en bruto que MySQL no tiene una comprensión inherente de. Con esto, puede crear un número arbitrario de campos de bits que MySQL se complace en tratar como valores binarios, hexadecimales o decimales, como lo necesite. Si necesita más de 64 opciones, cree tantos campos como sea apropiado para su aplicación. El inconveniente es que es difícil hacer que el campo sea legible por humanos. El tipo de datos BIT también está limitado a 64.
Si hay más que unas pocas banderas, o es probable que lo sea en el futuro, usaré una tabla de banderas separada y una tabla de muchas a muchas entre ellas.
Si hay un puñado de banderas y nunca voy a usarlas en un DONDE, usaré un SET () o bitfield o lo que sea. Son fáciles de leer y más compactos, pero un dolor de consulta y, a veces, incluso más de un dolor de cabeza con un ORM.
Si solo hay unas pocas banderas, y solo unas pocas banderas, haré un par de columnas BIT / BOOLEAN / etc.
Si las banderas tienen significados muy diferentes y se usan directamente en consultas SQL o VIEWS, entonces el uso de varias columnas de tipo BOOLEAN
podría ser una buena idea.
Ponga cada bandera en una columna adicional, porque las leerá y las modificará por separado de todos modos. Si desea agrupar las banderas, simplemente proporcione un prefijo común a sus nombres de columna, es decir, en lugar de:
CREATE TABLE ... (
warnings INTEGER,
errors INTEGER,
...
)
Deberías usar:
CREATE TABLE ... (
warning_foo BOOLEAN,
warning_bar BOOLEAN,
warning_...
error_foo BOOLEAN,
error_bar BOOLEAN,
error_... BOOLEAN,
...
)
Aunque MySQL no tiene un tipo BOOLEAN, puede usar el TINYINT cuasi estándar (1) para ese propósito, y establecerlo solo a 0 o 1.
Si realmente necesita una selección ilimitada de un conjunto cerrado de banderas (por ejemplo, identificadores de ), entonces la "forma relacional" sería crear una tabla de banderas y una tabla separada que relacione esas banderas con sus entidades objetivo. Por lo tanto, usuarios, banderas y usuariosToFlags.
Sin embargo, si la eficiencia del espacio es una preocupación seria y la capacidad de consulta no lo es, una máscara sin firma funcionaría casi tan bien.
Yo recomendaría usar un tipo de datos BOOLEAN si su base de datos lo admite.
De lo contrario, el mejor enfoque es usar NÚMERO (1) o equivalente, y poner una restricción de verificación en la columna que limita los valores válidos a (0,1) y quizás NULO, si es necesario. Si no hay un tipo incorporado, usar un número es menos ambiguo que usar una columna de caracteres. (¿Cuál es el valor para verdadero? "T" o "S" o "t")
Lo bueno de esto es que puedes usar SUM () para contar el número de filas VERDADERAS.
SELECT COUNT(1), SUM(ActiveFlag)
FROM myusers;
Un enfoque muy relacional
Para las bases de datos sin el tipo de conjunto, puede abrir una nueva tabla para representar el conjunto de entidades para las cuales se establece cada indicador.
Por ejemplo, para una tabla "Estudiantes", podría tener las tablas "Estudiantes registrados", "Estudiantes enfermos", "Estudiantes problemáticos", etc. Cada tabla tendrá solo una columna: student_id. Esto realmente sería muy rápido si todo lo que quiere saber es qué estudiantes están "Registrados" o "Enfermos", y funcionaría de la misma manera en cada DBMS.