MathSmath's answer is ok, but it's very inefficient and would not scale to a WordPress site with 100,000+ posts or what have you. Doing a WP_Query() for 1000 posts is going to be slow enough.
Rather than using a posts_not_it (which would pass a query long string if you hade several thousand posts here) if you have MySQL 4.1+ it would be better to use a subquery to exclude the posts you don't want.
Here is a slightly modified example I am using on a site with 250,000+ posts.
// add a filter to 'posts_where' to add the subquery
add_filter( 'posts_where', '_exclude_meta_key_in_posts_where' );
// make the query, the below function will be called
query_posts(array('showposts' => 1000, 'post_parent' => $post->ID, 'post_type' => 'page', 'orderby' => 'title', 'order' => 'ASC'));
function _exclude_meta_key_in_posts_where( $where ) {
global $wpdb;
return $where . " AND $wpdb->posts.ID NOT IN ( SELECT DISTINCT post_id FROM $wpdb->postmeta WHERE meta_key = 'featured_product' AND meta_value > '' )";
}
//remove the filter incase we do any more query_posts()s
remove_filter( 'posts_where', '_exclude_meta_key_in_posts_where' );
You could probably do it all in one create_function() though I am not sure if that is very efficient, but would be less lines:
// add a filter to 'posts_where' to add the subquery
add_filter( 'posts_where', create_function( '$where', 'global $wpdb; return $where . " AND $wpdb->posts.ID NOT IN ( SELECT DISTINCT post_id FROM $wpdb->postmeta WHERE meta_key = \'featured_product\' AND meta_value > \'\' )";' ) );
I didn't test the create_function() example.