Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Complex Wordpress query using multiple queries

So I have a query that works just fine if I run it directly in MySQL but fails if I run it through Wordpress $wpdb->query().

If I echo the $qry out to the page and copy and paste it in phpMyAdmin for example I get all the results I want. However in Wordpress I get an error.

The Error: WordPress database error: [You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'SELECT *, ROUND( 3963.0 * ACOS( SIN( 38.580983*PI()/180 ) * SIN( lat*PI()/18' at line 21]

The Query:

CREATE TEMPORARY TABLE tmp_locations_tbl
SELECT post.ID, 
        post.post_name, 
        lat_meta.meta_value AS lat, 
        lng_meta.meta_value AS lng, 
        address_meta.meta_value AS address
FROM wp_posts AS post, 
        wp_postmeta AS lat_meta, 
        wp_postmeta AS lng_meta, 
        wp_postmeta AS address_meta

WHERE post.ID = lat_meta.post_id 
AND post.ID = lat_meta.post_id 
AND post.ID = lng_meta.post_id 
AND lat_meta.meta_key = 'geo_latitude' 
AND lng_meta.meta_key = 'geo_longitude' 
AND address_meta.meta_key = 'address'

LIMIT 0, 5000;

SELECT *, 
ROUND( 3963.0 * ACOS( SIN( 38.580983*PI()/180 ) * SIN( lat*PI()/180 ) + COS( 38.580983*PI()/180 ) * COS( lat*PI()/180 ) * COS( (lng*PI()/180) - (-121.4931*PI()/180) ) ) , 1) 
AS distance
FROM tmp_locations_tbl
HAVING distance < 25
ORDER BY distance ASC
LIMIT 0, 200;

Clearly it doesn't like the ';' - or so I presume. But why does this run fine directly in MySQL and not Wordpress. Interestingly enough if I delete the ';' from the query that separates the two queries Wordpress doesnt return the right results and MySQL, through phpMyAdmin says it is an incorrect query.

Any help would be appreciated.

like image 699
P-Rick Stephens Avatar asked Aug 15 '13 05:08

P-Rick Stephens


People also ask

Can you run multiple SQL queries at once?

You can include multiple SQL statements on the SQL query panel. The exceptions are CALL and CREATE PROCEDURE statements.


2 Answers

This seems to be a limitation of PHP itself, see this post on the Wordpress forums.

I was faced with the same problem and ended up creating a custom function that does the job, I paste it here in case it is useful for someone. The function is rather simple since it does a few assumptions, but is should be easy to modify it to tailor different needs. Specifically it assumes that:

  • All statements are inserts and updates, there is no data to return.
  • Statements are separated with an end of line sequence.
  • Statements are enclosed within a transaction.

Here is the function:

function execute_multiline_sql($sql) {
    global $wpdb;
    $sqlParts = array_filter(explode("\r\n", $sql));
    foreach($sqlParts as $part) {
        $wpdb->query($part);
        if($wpdb->last_error != '') {
            $error = new WP_Error("dberror", __("Database query error"), $wpdb->last_error);
            $wpdb->query("rollback;");
            return $error;
        }
    }
    return true;
}

Usage example:

$sql = "start transaction;\r\n" .
       "insert into ...;\r\n" .
       "update ...;\r\n" .
       "commit;\r\n"
       ;

$result = execute_multiline_sql($sql);
if(is_wp_error($result)) {
    //Fail!
}
like image 172
Konamiman Avatar answered Sep 20 '22 01:09

Konamiman


Your code shows not one SQL statement, but rather two:

  1. CREATE TEMPORARY [...] LIMIT 0, 500;
  2. SELECT *, ROUND[...] LIMIT 0, 200;

As far as I remember, $wbdb->query() accepts only one statement at a time (at least the codex article doesn't point out it is designed for bulk queries, I haven't checked the class code to verify it).

Try putting those statements in two different variables, then run them one after the other, like this:

$SQL1 = "CREATE TEMPORARY [...] LIMIT 0, 500";
$SQL2 = "SELECT *, ROUND[...] LIMIT 0, 200";

$wpdb->query( $SQL1 );   
$wpdb->query( $SQL2 );
like image 44
Bjoern Avatar answered Sep 21 '22 01:09

Bjoern