Reputation: 14447
We are currently building a PostgreSQL database that allows us to create profiles for hardware. Each profile exists of a few different properties which are all dynamically added to the profile through the UI. Each property can be of a different type (string, integer, text, ...)
How would I most efficiently store these properties in a relational database?
I've read Storing diverse value types in a database and I'm charmed by the single answer there but I'm not at all confident that this is the ideal solution. Are there any pros/cons using the separate-table-per-type approach over the other solutions? Anyone has real world experience with this and minds shedding some light on the best approach?
Upvotes: 0
Views: 3914
Reputation: 656754
Use a column of data type text
.
Every data type in PostgreSQL has text representation - or else a plain pg_dump
would fail. Also, how would the user type in the value in the first place?
I have had several use cases like that for a couple of years now. No problems. You can store the actual data type in addition and cast the text representation if needed.
One disadvantage might be that the on-disc space for text representation will be higher for some types. But the overhead for multiple columns / tables may easily make up for that.
PostgreSQL is extremely versatile with indexing. I would solve a case like you mention in the comment with a partial index on an expression:
CREATE INDEX tbl_col_propx_idx ON tbl (cast(col AS int))
WHERE prop_type_id = 23; -- 23 signifying "propertyX"
And prop_type_id
would be a foreign key to a look-up table (foreign-key referenced):
CREATE TABLE prop_type(
prop_type_id int PRIMARY KEY,
prop_type text NOT NULL);
prop_type_id
could also be an enum
type. The handling of enums has been much improved in the latest version.
Then a query like this would be lightening fast:
SELECT *
FROM tbl
WHERE prop_type_id = 23 -- 23 signifying "propertyX"
AND col::int BETWEEN 50 AND 100
In addition, such an index would automatically validate the data type and throw an error if you'd try to enter string that doesn't match the type.
Alternatively, consider a document type like hstore
or json
/ josnb
(typically superior in modern Postgres).
Upvotes: 4
Reputation: 2679
My preferred way is single table with both key and value being varchar and/or text.
The only big disadvantage of table-per-type in that comment I can think of is that it's hard to constraint the uniqueness of the key in pair with the entity this key-value entry belongs to.
Table inheritance (but still with table-per-type) would be another way to go and IMHO it's brutally type-safe and compliant with postgres and ORM concepts:
CREATE TABLE key_values(user_id integer references users(id), key varchar(255), type varchar(255), CONSTRAINT UNIQUE(user_id, key));
CREATE TABLE key_values_int(value integer) INHERITS (key_values);
CREATE TABLE key_values_string(value varchar(255)) INHERITS (key_values);
and so on...
This perfectly maps to JPA.
Upvotes: 1