I have two nested queries, and the second is run as I iterate through the results of the first. I’d love to have the MySQL server do this work instead of PHP, but I can’t figure out how to combine these two.
the first query:
SELECT post_id,
MAX(CASE WHEN meta_key = 'size' THEN meta_value END) size,
MAX(CASE WHEN meta_key = 'adlink' THEN meta_value END) adlink,
MAX(CASE WHEN meta_key = 'frontpage' THEN meta_value END) frontpage,
MAX(CASE WHEN meta_key = 'expiration' THEN meta_value END) expiration,
MAX(CASE WHEN meta_key = 'image1' THEN meta_value END) image1,
MAX(CASE WHEN meta_key = 'image2' THEN meta_value END) image2,
MAX(CASE WHEN meta_key = 'image3' THEN meta_value END) image3,
MAX(CASE WHEN meta_key = 'image4' THEN meta_value END) image4,
MAX(CASE WHEN meta_key = 'iframe' THEN meta_value END) iframe,
MAX(CASE WHEN meta_key = 'location' THEN meta_value END) location,
MAX(CASE WHEN meta_key = 'sublocation' THEN meta_value END) sublocation
FROM wp_postmeta WHERE post_id in
(SELECT post_id from wp_postmeta
WHERE meta_value LIKE 'Run Of Site') GROUP BY Post_id
Then, iterating through the results, we get images from another table, as ‘image1’, etc., are only post id numbers in the first set of results:
SELECT meta_value FROM wp_postmeta
WHERE post_id IN
(SELECT meta_value from wp_postmeta
WHERE post_id = " . $row{'post_id'} ." AND meta_key like 'image%')
HERE’s the whole code to see PHP iteration (I KNOW it needs better formatting for readbility):
$rosads = mysql_query("SELECT post_id,
MAX(CASE WHEN meta_key = 'size' THEN meta_value END) size,
MAX(CASE WHEN meta_key = 'adlink' THEN meta_value END) adlink,
MAX(CASE WHEN meta_key = 'frontpage' THEN meta_value END) frontpage,
MAX(CASE WHEN meta_key = 'expiration' THEN meta_value END) expiration,
MAX(CASE WHEN meta_key = 'image1' THEN meta_value END) image1,
MAX(CASE WHEN meta_key = 'image2' THEN meta_value END) image2,
MAX(CASE WHEN meta_key = 'image1' THEN meta_value END) image3,
MAX(CASE WHEN meta_key = 'image2' THEN meta_value END) image4,
MAX(CASE WHEN meta_key = 'iframe' THEN meta_value END) iframe,
MAX(CASE WHEN meta_key = 'location' THEN meta_value END) location,
MAX(CASE WHEN meta_key = 'sublocation' THEN meta_value END) sublocation
FROM wp_postmeta WHERE post_id in (SELECT post_id from wp_postmeta WHERE meta_value LIKE 'Run Of Site') GROUP BY Post_id");
if (!$rosads) { // add this check.
die('Invalid query: ' . mysql_error());
}
while ($row = mysql_fetch_array($rosads)) { // ######### ITERATE THROUGH THE LIST
if ($row{'size'} == "Premium"){
if ($row{'iframe'}){
$premium = $premium . '<div name="PREMIUM'.$row{'post_id'}.'" style="float:left;">'.$row{'iframe'}.'</div>'."n";
}else{
$images = mysql_query("SELECT meta_value FROM wp_postmeta where post_id IN(SELECT meta_value from wp_postmeta WHERE post_id = " . $row{'post_id'} ." AND meta_key like 'image%')");
$premium = $premium . "<div name="".$row{'post_id'}."" class="multipleslides" >";
while ($row2 = mysql_fetch_array($images)) {
$premium = $premium . "t<a target="_blank" href="" . $row{'adlink'} .""><img src="/wp-content/uploads/" .$row2{'meta_value'} .""></a>rn";
}
$premium = $premium . "</div><br>";
}
/* ### TEST STUFF ####
echo $row{'post_id'} . ", " . $row{'size'} . ", " . $row{'adlink'} . ", " . $row{'frontpage'} . ", " . $row{'expiration'} . ", " . $row{'image1'} . ", " . $row{'image2'} . ", " . $row{'image3'} . ", " . $row{'image4'} . ", " . 1$row{'location'} . ", " . $row{'sublocation'} . ", " . $row{'iframe'} . "<hr>";
*/
} // ###### END THIS ITERATION ####
You can use your query as a column also but make sure your subquery should return one record for safe side i have added
LIMIT 1
in the subquery or if there are morethan 1 result you can remove the limit and can useGROUP_CONCAT(meta_value)
but baware it has a default limit of 1024 charactersFor the
group_concat()
To improve efficiency, replace the
IN (subquery)
with equivalent join operations, and ensure that you have suitable indexes in place.In the first query, replace this:
with this:
AND change the
post_id
reference in the SELECT list tom.post_id
(to avoid an “ambiguous column” reference error.)For the second query, replace the “IN (subquery)” with a JOIN operation:
Combining the two queries is problematic because the second query can return more than one row that matches on post_id.
To get result set returned, we need to define what that result set is going to look like.
There’s three general approaches. Briefly,
One way is to “repeat” the values returned by the first query, but that doesn’t look like a good fit with your current code. The “fetch next” would need to check if the post_id had already been processed, and ignore the duplicate values. (This is the approach used by several ORM frameworks to improve efficiency; those have a code layer that strips out the duplicates, and creates the distinct objects.)
Another way is to return a fixed number of values from the second query, each as a column in the second. Note that the SQL SELECT statement has to define the number of columns to return and the datatype of each. That can’t be changed dynamically when the query runs. If we can specify a finite upper bound of the number of rows to return, then we can craft SQL text to accomplish this, though the resulting statement can be a bit daunting, and there are some performance concerns.
The most convenient way to return a “set” of values is to return them as a single string, with delimiters. The MySQL
GROUP_CONCAT
function is a very handy way of doing that, with some limitations. First, we have to have a delimiter between the values; the default delimiter is a comma, but any character can be used (the “pipe” character seems to be pretty popular… to avoid ambiguity, we have to guarantee that the delimiter character does not appear in the values being concatenated together. The other limit is the size of the returned by the function; the maximum size is limited by the MySQLmax_allowed_packet
variable.