tags:

views:

25

answers:

4

Friends,

I have a strange need and cannot think my way through the problem. The great and mighty Google is of little help due to keyword recycling (as you'll see). Can you help?

What I want to do is store data of multiple types in a single column in MySQL.

This is the database equivalent to a C union (and if you search for MySQL and Union, you obviously get a whole bunch of stuff on the UNION keyword in SQL).

[Contrived and simplified case follows] So, let us say that we have people - who have names - and STORMTROOPERS - who have TK numbers. You cannot have BOTH a NAME and a TK number. You're either BOB SMITH -or- TK409.

In C I could express this as a union, like so:

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

This makes it so that I am either storing a pointer to a char array or an ID in the type EmperialPersonnelRecord, but not both.

I am looking for a MySQL equivalent on a column. My column would store either an int, double, or varchar(255) (or whatever combination). But would only take up the space of the largest element.

Is this possible?

(of course anything is possible given enough time, money and will - I mean is it possible if I am poor, lazy and on a deadline... aka "out of the box")

+1  A: 

No, there is no 'union' column type. But you can create a column that is big enough to hold the largest element and another column that works as type indicator. I.e.

... data VARCHAR(15), data_type enum('int','double','char')...
a1ex07
a1ex07 ~ that's a great answer, and it was where I was leaning. I was hoping to be able to do functions (min, max, sum) on the int types, string matching on the string types, etc. So that wouldn't quite work.So, in my dream world, I could do this: select * from table where WEIRD_COL.int between 1 and 10; select * from table where WEIRD_COL.string like "S*O*";etc.(not sure what the * would get me in the column list).
Michael
@user81338 - to do aggregation etc (which is a great point), you need to normalize into >1 table. See my answer below
DVK
+2  A: 

As a1ex07 said, you CAN do it by storing string representation. But if you are worried about space, storing real values in several NULLable columns will probably save more space.

Alternately, create ancillary tables and normalize, e.g.

Your want:

TABLE1
|id|name_or_TK#|

Your can do:

TABLE1
|id|name|TK|

or you can do

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|
DVK
DVK - space and performance are my primary concerns. I did not know that you save space with null-able columns - I thought that the space was allocated for them and the value was simply not there.Excellent options - thank you.
Michael
You won't save space for fixed length columns (e.g. ints) but will definitely save on varchar ones. See http://stackoverflow.com/questions/556363/space-used-by-nulls-in-database for a good intro
DVK
As for performance, the difference between 2d and 3d solution depends entirely on which queries will be run on the table(s), but both will definitely easily beat the "store everything in a character encoding) due to the need to convert to other datatypes.
DVK
@Michael - if this answered your question, please feel free to accept the answer by clicking on the checkmark next to it :)
DVK
DVK - you got it. I was double checking the null/var length answer.Thanks.
Michael
DVK - also, that was a very polite way of nudging one to CLICK THE FLIPPING CHECK MARK ALREADY. I appreciate your tact. =)
Michael
A: 

C unions are a pretty bit-twiddly way of handling this problem.

What you have there is a polymorphic data type. So, one way to solve the problem is to switch to an object-oriented DB, or one that is dynamically typed, like some of the "NoSQL" ones.

If you have to stay with the current relational DB, you can do the standard thing which is to build some kind of ORM -- object-relational mapper -- to do the translation. One way is to put the common ("base class") fields in the main table, along with a type column, then use the type column to select which "leaf class" table holds the additional fields. For instance:

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

That is, the *Employee tables are tied back to the base Employee table by employee ID.

Warren Young
I chuckled at the idea of a storm trooper having a mid-level manager. :)I agree on unions being weird, but I am trying to get the problem reduced to the most atomic (smallest indivisible, not radioactive) case and that kind of describes it.
Michael
A: 

I think you should have 2 different columns and store data accordingly, when retrieving you can cast and append them together something like col1 + col2 as full_name

Daniel Luyo