Sane way to store different data types within same column in postgres?

You can use 2 different technics:

  1. if you have floating type for every tagid

Define table and ID for every tagid-assetid combination and actual data tables:

maintable:
+---------------+----------------+-----------------+---------------+
|assetid (text) | tagid(integer) | tablename(text) | table_id(int) |
|---------------+----------------+-----------------+---------------|
|someStringValue| 1234           | tablebool       | 123           |
|---------------+----------------+-----------------+---------------|
|aDiffStringKey | 1235           | tablefloat      | 123           |
|---------------+----------------+-----------------+---------------|
|aDiffStrKey    | 1236           | tablestring     | 123           |
+---------------+----------------+-----------------+---------------+

tablebool
+-------------+-------------+
| id(integer) | value(bool) |
|-------------+-------------|
| 123         | False       |
+-------------+-------------+

tablefloat
+-------------+--------------+
| id(integer) | value(float) |
|-------------+--------------|
| 123         | 12.345       |
+-------------+--------------+

tablestring
+-------------+---------------+
| id(integer) | value(string) |
|-------------+---------------|
| 123         | 'text'        |
+-------------+---------------+
  1. In case if every tagid has fixed type

create tagid description table

tag descriptors
+---------------+----------------+-----------------+
|assetid (text) | tagid(integer) | tablename(text) |
|---------------+----------------+-----------------|
|someStringValue| 1234           | tablebool       |
|---------------+----------------+-----------------|
|aDiffStringKey | 1235           | tablefloat      |
|---------------+----------------+-----------------|
|aDiffStrKey    | 1236           | tablestring     |
+---------------+----------------+-----------------+

and correspodnding data tables

tablebool
+-------------+----------------+-------------+
| id(integer) | tagid(integer) | value(bool) |
|-------------+----------------+-------------|
| 123         | 1234           | False       |
+-------------+----------------+-------------+

tablefloat
+-------------+----------------+--------------+
| id(integer) | tagid(integer) | value(float) |
|-------------+----------------+--------------|
| 123         | 1235           | 12.345       |
+-------------+----------------+--------------+

tablestring
+-------------+----------------+---------------+
| id(integer) | tagid(integer) | value(string) |
|-------------+----------------+---------------|
| 123         | 1236           | 'text'        |
+-------------+----------------+---------------+

All this is just for general idea. You should adapt it for your needs.


Another option, depending on what your doing, could be to just have one value column but store some json around the value...

This could look something like:

  {
    "type": "datetime",
    "value": "2019-05-31 13:51:36" 
  } 

That could even go a step further, using a Json or XML column.


I'm not in any way PostgreSQL ninja, but I think that instead of two columns (one for name and one for type) you could look at hstore data type:

data type for storing sets of key/value pairs within a single PostgreSQL value. This can be useful in various scenarios, such as rows with many attributes that are rarely examined, or semi-structured data. Keys and values are simply text strings.

Of course, you have to check how date/timestamps converting into and from this type and see if it good for you.


You've basically got two choices:

Option 1: A sparse table

Have one column for each data type, but only use the column that matches that data type you want to store. Of course this leads to most columns being null - a waste of space, but the purists like it because of the strong typing. It's a bit clunky having to check each column for null to figure out which datatype applies. Also, too bad if you actually want to store a null - then you must chose a specific value that "means null" - more clunkiness.

Option 2: Two columns - one for content, one for type

Everything can be expressed as text, so have a text column for the value, and another column (int or text) for the type, so your app code can restore the correct value in the correct type object. Good things are you don't have lots of nulls, but importantly you can easily extend the types to something beyond SQL data types to application classes by storing their value as json and their type as the class name.

I have used option 2 several times in my career and it was always very successful.