2010-03-16 9 views
6

Amigos,ejecución de una c/C++ unión de estilo como una columna en MySQL

que tienen una extraña necesidad y no pueden pensar en mi camino a través del problema. El gran y poderoso Google es de poca ayuda debido al reciclaje de palabras clave (como verás). ¿Puede usted ayudar?

Lo que quiero hacer es almacenar datos de múltiples tipos en una sola columna en MySQL.

Esta es la base de datos equivalente a una unión C (y si busca MySQL y Union, obviamente obtiene un montón de cosas sobre la palabra clave UNION en SQL).

[Sigue el caso simplificado y modificado] Por lo tanto, digamos que tenemos personas, que tienen nombres, y STORMTROOPERS, que tienen números TK. No puedes tener TANTO un NOMBRE como un número de TK. Eres BOB SMITH o TK409.

En CI puede expresar esto como una unión, así:

union { 
     char * name; 
     int tkNo; 
     } EmperialPersonnelRecord; 

Esto hace que sea para que yo estoy bien almacenando un puntero a una matriz de caracteres o un ID en el tipo EmperialPersonnelRecord, no, pero ambos.

Estoy buscando un equivalente de MySQL en una columna. Mi columna almacenaría un int, double o varchar (255) (o la combinación que sea). Pero solo tomaría el espacio del elemento más grande.

¿Esto es posible?

(por supuesto todo es posible dado suficiente tiempo, dinero y voluntad - quiero decir es posible si yo soy pobre, perezoso y en un plazo ... también conocido como "fuera de la caja")

+0

respondí con una forma de hacerlo, pero puede por favor elaborar ¿POR QUÉ quieres/necesito? Parece que la solución obvia de almacenar todos los atributos separados en columnas separadas NULL funcionaría muy bien – DVK

Respuesta

3

Como dijo a1ex07, PUEDE hacerlo guardando la representación de la cadena. Pero si le preocupa el espacio, almacenar valores reales en varias columnas NULL probablemente ahorrará más espacio.

De forma alternativa, cree tablas auxiliares y normalícelas, p.

vuestra falta

 
TABLE1 
|id|name_or_TK#| 

Tu puede hacer:

 
TABLE1 
|id|name|TK| 

o puede hacerlo

 
TABLE1 
|id|ST_or_human_flag|other columns common to humans and stormtroopers 

TABLE2 - Names_of_humans 
|id|name| 

TABLE3 - TKs_of_STs 
|id|TK| 
+0

DVK - el espacio y el rendimiento son mis principales preocupaciones. No sabía que se ahorra espacio con columnas que no pueden anotar; pensé que el espacio estaba asignado para ellos y que el valor simplemente no estaba allí. Excelentes opciones, gracias. – Michael

+0

No ahorrará espacio para columnas de longitud fija (por ejemplo, ints) pero definitivamente se guardará en varchar. Consulte http://stackoverflow.com/questions/556363/space-used-by-nulls-in-database para obtener una buena introducción – DVK

+0

En cuanto al rendimiento, la diferencia entre la solución 2D y 3D depende completamente de qué consultas se ejecutarán en el mesa (s), pero ambos definitivamente vencerán fácilmente a "almacenar todo en una codificación de caracteres" debido a la necesidad de convertir a otros tipos de datos. – DVK

1

No, no hay ningún tipo de columna 'unión'. Pero puede crear una columna que sea lo suficientemente grande como para contener el elemento más grande y otra columna que funcione como indicador de tipo. Es decir.

... data VARCHAR(15), data_type enum('int','double','char')... 
+0

a1ex07 ~ esa es una gran respuesta, y fue donde me inclinaba. Tenía la esperanza de poder hacer funciones (min, max, sum) en los tipos int, coincidencia de cadenas en los tipos de cadenas, etc. Así que eso no funcionaría. Entonces, en mi mundo de sueños, podría hacer esto: seleccionar * de la tabla donde WEIRD_COL.int entre 1 y 10; select * from table donde WEIRD_COL.string como "S * O *"; etc. (no estoy seguro de qué obtendría * en la lista de columnas). – Michael

+0

@ user81338 - para hacer la agregación, etc. (que es un gran punto), necesita normalizar en> 1 tabla. Ver mi respuesta a continuación – DVK

1

C sindicatos son una forma bastante poco-twiddly de manejar este problema.

Lo que tienes allí es un tipo de datos polimórficos. Por lo tanto, una forma de resolver el problema es cambiar a una base de datos orientada a objetos, o una que se escribe de forma dinámica, como algunos de los "NoSQL".

Si tiene que quedarse con la base de datos relacional actual, puede hacer lo estándar que es construir algún tipo de asignador ORM - objeto relacional - para hacer la traducción.Una forma es colocar los campos comunes ("clase base") en la tabla principal, junto con una columna de tipo, luego usar la columna de tipo para seleccionar qué tabla de "clase de hoja" contiene los campos adicionales. Por ejemplo:

table Employee 
    field id int 
    field emp_type enum('human', 'stormtrooper') 
    field salary int 
    field division_id int 
    field manager_id int 

table HumanEmployee 
    field emp_id int 
    field name string 

table StormtrooperEmployee 
    field emp_id int 
    field tk_number int 

Es decir, las * tablas de empleados están vinculadas a la tabla de empleados base por ID de empleado.

+1

Me reí de la idea de que un soldado de asalto tuviera un gerente de nivel medio. :) Estoy de acuerdo en que los sindicatos son extraños, pero trato de reducir el problema al caso más atómico (el indivisible más pequeño, no radiactivo) y eso lo describe. – Michael

0

creo que debería tener 2 columnas diferentes y almacenar datos en consecuencia, cuando se recuperan puede convertir y añadir juntos algo así como col1 + col2 como FULL_NAME

Cuestiones relacionadas