I've searched about this and tried to make it myself over the last few days but I just couldn't. The closest I've gotten within my search was this answer, also on Stack Overflow: EAV Select query from spreaded value tables
So here I am, turning myself to the Internet!
So, I have a database which makes use of the EAV (Entity-Attribute-Value) model. But here's the catch: the actual entities aren't directly connected to the other EAV tables. Let me be more specific; say that there is a Person and a Site tables, and that they only have their primary keys: person_id and site_id, respectively.
Because the attributes (called "properties" on my schema) of those entities (i.e. the Person and the Site) must be dynamic, they must all be stored outside their respective tables, i.e. the EAV tables. The following is the EAV part of the database schema (I'm not sure if it's completely correct, so please let me know if you have any suggestion). -- http://i.stack.imgur.com/EN3dy.png
The EAV part of the schema basically has the following tables:
propertyproperty_value_varcharproperty_value_textproperty_value_numberproperty_value_booleanproperty_value_datetimeentity_tables
Ok, so, since the Entities aren't "directly connected" to the EAV part, I'm using the entity_tables table just as a reference to the actual tables, so, with the example above, the entity_tables table should look something like this:
--------------------------------------- |entity_table_id | entity_table_name | | 1 | person | | 2 | site | | . | . | | . | . | ---------------------------------------
The property table is the one that actually holds the different properties that any entity can hold, say "PERSON_FIRST_NAME" or "LOCATION_NAME", or anything else.
The property_value_* tables are all exactly the same except on the datatype of the property_value. These are the ones that hold the actual value of each Entity's object's property, which get mapped by the entity_table_id and entity_object_id.
Let me give you a possible instance of the database, for clarity:
Person table ------------- | person_id | | 1 | | 2 | ------------- Site table ----------- | site_id | | 1 | | 2 | ----------- entity_tables table --------------------------------------- |entity_table_id | entity_table_name | | 1 | person | | 2 | site | --------------------------------------- property table ------------------------------------- | property_id | property_code | | 1 | PERSON_FIRST_NAME | | 2 | PERSON_LAST_NAME | | 3 | PERSON_BIRTH_DATE | | 4 | SITE_NAME | | 5 | SITE_PHONE_NR_1 | | 6 | SITE_PHONE_NR_2 | | 7 | SITE_LATITUDE | | 8 | SITE_LONGITUDE | | 9 | SITE_CITY | | 10 | SITE_COUNTRY | | 11 | SITE_ZIP_CODE | ------------------------------------- property_value_varchar table ----------------------------------------------------------------------------------------- | property_value_id | property_id | entity_table_id | entity_object_id | property_value | | 1 | 1 | 1 | 1 | Richard | | 2 | 2 | 1 | 1 | Hammer | | 3 | 1 | 1 | 2 | Bruce | | 4 | 2 | 1 | 2 | Heaton | | 5 | 4 | 2 | 1 | BatCave | | 6 | 5 | 2 | 1 | +49123456789 | | 7 | 4 | 2 | 2 | BigCompany | | 8 | 5 | 2 | 2 | 987654321 | | 9 | 6 | 2 | 2 | 147852369 | | 10 | 9 | 2 | 2 | Berlin | | 11 | 10 | 2 | 2 | Germany | | 12 | 11 | 2 | 2 | 14167 | ----------------------------------------------------------------------------------------- property_value_datetime table ----------------------------------------------------------------------------------------- | property_value_id | property_id | entity_table_id | entity_object_id | property_value | | 1 | 3 | 1 | 1 | 1985-05-31 | ----------------------------------------------------------------------------------------- property_value_number table ----------------------------------------------------------------------------------------- | property_value_id | property_id | entity_table_id | entity_object_id | property_value | | 1 | 7 | 2 | 1 | 1.402636 | | 2 | 8 | 2 | 1 | 7.273922 | ----------------------------------------------------------------------------------------- (property_value_text and property_value_boolean tables are empty)
As you could see, not all objects of each entity have necessarily the same properties (attributes). The domain is really loose like that.
So, now like so many people before me, I'm not sure how to retrieve all of this information in a readable way, namely how can I get all of the information concerning the records of the Person table or of the Site table?
Namely, how can I get something like this:
Person table view ---------------------------------------------------- | Person ID | Property code | Property value | | 1 | PERSON_FIRST_NAME | Richard | | 1 | PERSON_LAST_NAME | Hammer | | 1 | PERSON_BIRTH_DATE | 1985-05-31 | | 2 | PERSON_FIRST_NAME | Bruce | | 2 | PERSON_LAST_NAME | Heaton | ---------------------------------------------------- Site table view ------------------------------------------------ | Site ID | Property code | Property value | | 1 | SITE_NAME | Batcave | | 1 | SITE_PHONE_NR_1 | +49123456789 | | 1 | SITE_LATITUDE | 1.402636 | | 1 | SITE_LONGITUDE | 7.273922 | | 2 | SITE_NAME | BigCompany | | 2 | SITE_PHONE_NR_1 | 987654321 | | 2 | SITE_PHONE_NR_2 | 147852369 | | 2 | SITE_CITY | Berlin | | 2 | SITE_COUNTRY | Germany | | 2 | SITE_ZIP_CODE | 14167 | ------------------------------------------------
Or even like this, if it is easier:
Person table view ------------------------------------------------------------------------ | Person ID | PERSON_FIRST_NAME | PERSON_LAST_NAME | PERSON_BIRTH_DATE | | 1 | Richard | Hammer | 1985-05-31 | | 2 | Bruce | Heaton | | ------------------------------------------------------------------------ Site table view ---------------------------------------------------------------------------------------------------------------------------------------- | Site ID | SITE_NAME | SITE_PHONE_NR_1 | SITE_PHONE_NR_2 | SITE_LATITUDE | SITE_LONGITUDE | SITE_CITY | SITE_COUNTRY | SITE_ZIP_CODE | | 1 | Batcave | +49123456789 | | 1.402636 | 7.273922 | | | | | 2 | BigCompany | 987654321 | 147852369 | | | Berlin | Germany | 14167 | ----------------------------------------------------------------------------------------------------------------------------------------
I realize this can be quite confusing. Please let me know how else I can help you help me, like more information or better explaining of some part.
I also don't expect 1 SQL query (per entity) to do the trick. I realize that more than 1 query is likely and that it/they would very likely need to be "assembled" by PHP (for instance), in order to really make it dynamic. So even if someone could even just explain me how I could get all of this info just for the hypothetical properties (attribute) that I have above, I would already be immensely grateful!
Thank you for any help!
SELECTquery column cannot depend on the contents of a table -- it must be known at query time, or discoverable from the type of a table column or expression, so the only way to write a query that would produce output like your first example would be to join on everyresult_value_...table and merge... - j_random_hackerCOALESCE()or similar. But then the type of the column will necessarily become some lowest-common-denominator type (probably unboundedVARCHAR), so you can't perform most sensible operations on them (e.g. you could not add 5 to each value, even if you knew they were originally numeric, without first explicitly converting to a numeric type). Some RDBMSs (perhaps MySQL, I dunno) have "pivoting" extensions that might allow rows to be converted into columns as per your later snippets, but this is TTBOMK not standard SQL. - j_random_hackerINFORMATION_SCHEMA) and then build a customisedSELECTcommand from that. - j_random_hackerALTER TABLEcommands from their input, but I think a better (safer) solution would be to... - j_random_hacker