You are looking for Dynamic pivot tables.
Code:
SET @sql = NULL;
SELECT
GROUP_CONCAT(DISTINCT
CONCAT(
'MAX(IF(pa.extractorname = ''',
extractorname,
''', p.data, NULL)) AS ',
extractorname
)
) INTO @sql
FROM extractors;
SET @sql = CONCAT('SELECT c.url, ',
@sql,
' FROM crawlresults c',
' INNER JOIN extractions p on (c.id = p.fk_crawlresults_id)',
' INNER JOIN extractors pa on (p.fk_extractors_id = pa.id)'
' WHERE c.fk_crawljobs_id = 1',
' GROUP BY c.id');
PREPARE stmt FROM @sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
Basically your original query was generating a bogus @sql
variable which didn't really extract data
for each extractorname
. You also don't need all of those joins for creating @sql
. You only need each one of the property names (from extractor
table) and a reference to the column holding the expect values (data
).
When in doubt about the structure, write out a simple pivot query for a fixed set of properties. This way it becomes easy to identify the pattern for writing the dynamic query.
SELECT c.url,
MAX(IF(pa.extractorname = 'price', p.data, NULL)) AS price,
MAX(IF(pa.extractorname = 'article', p.data, NULL)) AS article,
MAX(IF(pa.extractorname = 'imageurl', p.data, NULL)) AS imageurl
FROM crawlresults c
LEFT JOIN extractions p on (c.id = p.fk_crawlresults_id)
LEFT JOIN extractors pa on (p.fk_extractors_id = pa.id)
WHERE c.fk_crawljobs_id = 1
GROUP BY c.id
As for the rest of your query it is fine, just keep in mind that the LEFT JOINS
could be useful if there are no extractions
for some crawlresults
. Also if your table can contain more than one crawlresult
per url
/ fk_crawljobs_id
, grouping by url
is a bad idea (MAX
can potentially mix the results from multiple extractions
).