Q:

MySQL EAV SELECT one-to-many single row results

I've seen similar questions on here, but haven't been able to find one that matches my specific scenario.  I have the following three tables:
content
id, [other fields]

attributes
id, title

attributes_values
id, attribute_id[foreign to attributes.id], content_id[foreign to content.id], value

What I'd like is a single query (or group of sub-queries) that can return the appropriate data to avoid having to manipulate this in the programming.
A little more info about the tables: attributes has three records (Model #, Part #, and Show in Cart).
I need to select all records from content where the attribute_value for Show in Cart = 1. Along with this, I'd like the other related attribute_values to be returned as their related attribute.title. The results would look something like this:
id    [other fields]    Model # [from attributes.title field]    Part # [from attributes.title field]
1     [any data]        value from attributes_values             value from attributes_values
2     [any data]        value from attributes_values             value from attributes_value

So far, my only way of accomplishing this is not very elegant as I'm having to do multiple joins to the same table:
SELECT * FROM content AS a
LEFT JOIN attributes_values AS b ON (b.content_id = a.id AND b.attribute_id = [Model # ID])
LEFT JOIN attributes_values AS c ON (c.content_id = a.id AND c.attribute_id = [Part # ID])
WHERE a.id IN (
    SELECT content_id FROM attributes_values WHERE attribute_id = [Show in Cart ID] AND value = 1
)

As you can see, I'm having to hard-code related keys into the JOIN statements, which doesn't make this very scalable (and just feels dirty).
Some last few notes: I'm using PHP and Joomla!, so if that would affect your answer (or if there's some secret Joomla tip), feel free to include it.  Also, this is a pre-established table schema that I'm not able to alter, so I need a query solution for the above mentioned tables, not a suggestion on a better table design.
Any help will be greatly appreciated.
Cheers!

A:

Instead of joining your table multiple times for each attribute, you can use an aggregated function like MAX() in combination with a CASE WHEN statement:
SELECT
  content.id,
  [other_fields],
  MAX(CASE WHEN attributes.title='Model #' THEN attributes_values.value END) AS Model_N,
  MAX(CASE WHEN attributes.title='Part #' THEN attributes_values.value END) AS Part_N
FROM
  content INNER JOIN attributes_values
  ON content.id = attributes_values.content_id
  INNER JOIN attributes
  ON attributes_values.attribute_id = attributes.id
GROUP BY
  id,
  [other_fields]
HAVING
  MAX(CASE WHEN attributes.title='Show in Cart' THEN attribute_values.value END)='1'

a little explanation:
CASE WHEN attributes.title='Model #' THEN attributes.value END

will return the value when the attribute is 'Model #' and NULL otherwise, and
MAX(...)

will return the maximum non-NULL value, which is the value where attributes.title='Model #'.
dynamic attributes
MySQL does not have a Pivot function, so if you want your list to be dynamic, you have to dinamically create a SQL string with all attributes and execute this string.
You can fetch all attributes from the attributes table:
SELECT
    CONCAT(
      'MAX(CASE WHEN attributes.title=''',
      REPLACE(attributes.title, '''', ''''''),
      ''' THEN attributes_values.value END) AS `',
      REPLACE(attributes.title, '`', '``'),
      '`'
    )
FROM
  attributes;

and combine everything together with GROUP_CONCAT:
SELECT GROUP_CONCAT(...the concat above...)
FROM attributes;

so your final query will be something like this:
SELECT
  CONCAT('SELECT content.id,',

  GROUP_CONCAT(
    CONCAT(
      'MAX(CASE WHEN attributes.title=''',
      REPLACE(attributes.title, '''', ''''''),
      ''' THEN attributes_values.value END) AS `',
      REPLACE(attributes.title, '`', '``'),
      '`'
    )
  ),

  ' FROM content INNER JOIN attributes_values ',
  'ON content.id = attributes_values.content_id ',
  'INNER JOIN attributes ',
  'ON attributes_values.attribute_id = attributes.id ',
  'GROUP BY id HAVING ',
  'MAX(CASE WHEN attributes.title=''Show in Cart'' THEN attributes_values.value END)=''1'''
  )
FROM
  attributes
INTO @SQL;

now the @SQL variable will hold the value of the query to be executed, and you can execute it with:
PREPARE stmt FROM @sql;
EXECUTE stmt;

The only problem here is that GROUP_CONCAT has a maximum length limit, you can increase it if your table is holding many attributes.
Please see an example fiddle here.

