Tell me more ×
WordPress Answers is a question and answer site for WordPress developers and administrators. It's 100% free, no registration required.

I use Advanced Custom Fields and have a custompost-type "matches". This post-type contains two fields "goals-made" and "goals-against".

I want to query wordpress to show only the matches that were won. So where "goals made" > "goals-against".

Can anyone help me get started on this one. The goal is to have a statistics page in the end.

Thx a lot for helping me out

share|improve this question
 
I think that only chance is retrieving the posts that have both the meta fields and then looping trought them and do the comparison. Can be low performant but I don't see any other solution. If someone gives a better one, will get my +1 for sure. –  G. M. Sep 10 at 13:33

3 Answers

I think something like this, but not tested, and my SQL-foo is rather weak:

    $test = $wpdb->get_col( $wpdb->prepare(
    "
    SELECT DISTINCT    $wpdb->posts.*
    FROM               $wpdb->posts
    INNER JOIN         $wpdb->postmeta AS mt1 ON (
         wp_posts.ID = $wpdb->postmeta.post_id
    )
    WHERE              $wpdb->postmeta.meta_key = 'goals-made'
    AND(               mt1.meta_key = 'goals-against'
        AND            CAST($wpdb->postmeta.meta_value AS INT) > CAST(mt1.meta_value AS INT)
    )

    "
));

This should return a list of post_ids that you can then process. But then again, it might just fail miserably.

share|improve this answer
 
This do not compare for >. To retrieve post that have both fileds, and the looping and do the compare, it's possible to use the standard meta_query, with relation 'AND': 'meta_query' => array('relation'=>'AND', array('key' => 'goals-made'), array('key' => 'goals-against') ) –  G. M. Sep 11 at 0:31
 
What you describe does not inherently compare either, however. If you perform a combined meta_query, it is probably simpler to do the comparison afterwards. While I am not confident in the exact structure of my query, it should be comparing those two values as cast integers. –  GhostToast Sep 11 at 1:25
 
Ah, ok, my bad, I don't read your sql well. (I miss the '>' between the 2 cast). Ave you tested? I'm going to. –  G. M. Sep 11 at 3:13
2  
Men, you got +1 this time! :) There was only few MySQL syntax errors on your query, but it's the right direction! The working and tested version: $wpdb->get_col("SELECT DISTINCT $wpdb->posts.ID FROM $wpdb->posts INNER JOIN $wpdb->postmeta AS mt1 ON ( wp_posts.ID = mt1.post_id ) INNER JOIN $wpdb->postmeta AS mt2 ON ( wp_posts.ID = mt2.post_id ) WHERE mt1.meta_key = 'goals-made' AND( mt2.meta_key = 'goals-against' AND CAST(mt1.meta_value AS UNSIGNED) > CAST(mt2.meta_value AS UNSIGNED))"). –  G. M. Sep 11 at 18:23
1  
Nice. And Mister Melotte was never seen or heard from again lol ;) –  GhostToast Sep 11 at 18:39
show 5 more comments

If I was in your situation, I'd used a different approach.

Simply add an hidden meta field automatically when goals_made is updated.

E.g.

add_action('updated_postmeta', 'update_goal_made', 20, 4);

function update_goal_made( $meta_id, $object_id, $meta_key, $_meta_value ) {
  if ( $meta_key != 'goals-made') return; // run only when update meta 'goals-made'
  // get the goals-against for post
  $against = get_post_meta($object_id, 'goals-against', true) ? : 1;
  // if 'goals-made' > 'goals-against' create/update a field '_goals-won' setted to 1
  if ( intval($_meta_value) > intval($against) ) {
    update_post_meta($object_id, '_goals-won', '1');
  } else {
    // if not delete '_goals-won' post meta (if exists)
    delete_post_meta($object_id, '_goals-won');
  }
}

Now to retrieve the posts where _goals-won exists, simply run a meta query:

$args = (
  'posts_per_page' => -1,
  'meta_query' => array( array('meta_key'=>'_goals-won') )
);
$won_posts = get_posts($args);

EDIT

After some works on GhostToast answer I can give you also the right SQL query to get the same result.

global $wpdb;
$won_posts = $wpdb->get_results( "
    SELECT $wpdb->posts.* 
        FROM $wpdb->posts
    INNER JOIN $wpdb->postmeta AS mt1 ON ( $wpdb->posts.ID = mt1.post_id )
    INNER JOIN $wpdb->postmeta AS mt2 ON ( $wpdb->posts.ID = mt2.post_id )
    WHERE mt1.meta_key = 'goals-made' 
        AND ( 
            mt2.meta_key = 'goals-against'
            AND CAST( mt1.meta_value AS UNSIGNED ) > CAST( mt2.meta_value AS UNSIGNED )
        )
    GROUP BY $wpdb->posts.ID
" );

Side note:

If someone write the SQL statement that handle your request, sure that SQL statement will be less performant then the simplest meta query like the first posted.

share|improve this answer
 
This is certainly the "least work" approach, and I support that. But also very curious to see a custom sql statement which handles this. I started to write one but moved on ;) –  GhostToast Sep 10 at 14:11
1  
If someone writes that sql statement will get my +1 and my boundless admiration ;) @GhostToast –  G. M. Sep 10 at 14:16
 
+1 for the query. Just two questions: (1) Why do you have to join the table twice instead of simply using the first one? Or couldn't you simply use $wpdb->postmeta instead of the alias? (2) Why do you use UNSIGNED instead of INT? –  kaiser Sep 12 at 12:31
1  
@kaiser (1) Without the 2nd JOIN the query doesn't work (because the WHERE clause look for an unknown table, once the meta table is treated as 2 different tables to make query works). Of course I can join using $wpdb->postmeta, reason for another alias is just aestetic :) (2) For some reason (I'm not an SQL expert) INT doesn't work. Looking in official MySQL 5.1 docs it doesn't figure among supported types for CAST. –  G. M. Sep 12 at 13:23
1  
@kaiser how can I +1 an edit? :) Damn GhostToast! (I'm joking) –  G. M. Sep 12 at 13:47
show 2 more comments

Hope I didn't understand the question wrong :)

$results = new WP_Query( array(
    'post_type'  => 'matches',
    'meta_query' => array(
        array(
            'key'     => 'goals-made',
            'value'   => (int) get_post_meta( get_the_ID(), 'goals-against',  true ),
            'type'    => 'INT',
            'compare' => ">",
        )
    ),
) );
if ( $results->have_posts() )
{
    while ( $results->have_posts() )
    {
        the_post();
        var_dump( $GLOBALS['post'] );
    }
}

As we don't know from where you're doing this query, simply replace get_the_ID() inside get_post_meta() with the retrieved ID of the posts you want to compare against.

share|improve this answer
 
mmm, the OP don't want compare posts agains one specific post, but want retrieve all posts that not only have both two meta fields, but also one meta value is > the other meta value, but both fields attached to post itself. I dont't know if it's more clear now... –  G. M. Sep 11 at 0:26

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.