web-dev-qa-db-fra.com

En utilisant OR conditions dans meta_query pour l'argument query_posts

J'ai cherché haut et bas pour cela, mais je n'arrive pas à localiser quoi que ce soit.

J'essaie de filtrer certains résultats et lorsque je crée un tableau args comme celui-ci et que je le passe à query_posts, j'ai constaté que le code SQL généré utilise AND au lieu de OR pour la valeur 'class_1_days'. Je voudrais faire qu'un OU. Comment pourrais-je m'y prendre? (J'utilise LIKE là-bas car les données sont sérialisées, sinon j'aurais essayé un "IN" et passé un tableau. Quelle est la bonne façon de s'y prendre?

$args = array(
            'taxonomy' => 'courses', 
            'term' => 'drawing', 
            'post_type' => 'school', 
            'paged' => $paged,
            'meta_query' =>
                #$checkbox_array,
                array(
                    array(
                        'key' => 'instructor',
                        'value' => '1128',
                        'compare' => 'LIKE',
                    ),
                    array(
                        'key' => 'class_1_days',
                        'value' => 'Friday',
                        'compare' => 'LIKE',
                    ),
                    array(
                        'key' => 'class_1_days',
                        'value' => 'Saturday',
                        'compare' => 'LIKE',
                    ),
                )

        );

Ceci est le SQL pertinent qui est généré où j'ai remarqué le AND

[138] => Array
    (
        [0] => SELECT SQL_CALC_FOUND_ROWS  wp_posts.ID FROM wp_posts  INNER JOIN     wp_term_relationships ON (wp_posts.ID = wp_term_relationships.object_id) INNER JOIN     wp_postmeta ON (wp_posts.ID = wp_postmeta.post_id)
INNER JOIN wp_postmeta AS mt1 ON (wp_posts.ID = mt1.post_id)
INNER JOIN wp_postmeta AS mt2 ON (wp_posts.ID = mt2.post_id) WHERE 1=1  AND (     wp_term_relationships.term_taxonomy_id IN (18) ) AND wp_posts.post_type = 'school' AND     (wp_posts.post_status = 'publish' OR wp_posts.post_status = 'private') AND (     (wp_postmeta.meta_key = 'instructor' AND CAST(wp_postmeta.meta_value AS CHAR) LIKE '%1128%')
AND  (mt1.meta_key = 'class_1_days' AND CAST(mt1.meta_value AS CHAR) LIKE '%Friday%')
AND  (mt2.meta_key = 'class_1_days' AND CAST(mt2.meta_value AS CHAR) LIKE '%Saturday%') ) GROUP BY wp_posts.ID ORDER BY wp_posts.post_date DESC LIMIT 0, 5
3
Devario Johnson

Utilisez 'relation' => 'OR'comme dans l'exemple du Codex ci-dessous:

$args = array(
    'post_type' => 'product',
    'meta_query' => array(
        'relation' => 'OR', /* <-- here */
        array(
            'key' => 'color',
            'value' => 'blue',
            'compare' => 'NOT LIKE'
        ),
        array(
            'key' => 'price',
            'value' => array( 20, 100 ),
            'type' => 'numeric',
            'compare' => 'BETWEEN'
        )
    )
);
$query = new WP_Query( $args );

Cela vous donnera une OR dans tous vos blocs meta_query. Si vous avez besoin de quelque chose comme WHERE "instructor" = 1128 AND (class_1_days = "value1" OR class_1_days = "value2"), quelque chose comme ceci le ferait si vos données n'étaient pas sérialisées.

$args = array(
        'taxonomy' => 'courses', 
        'term' => 'drawing', 
        'post_type' => 'school', 
        'paged' => $paged,
        'meta_query' =>
            array(
                array(
                    'key' => 'instructor',
                    'value' => '1128',
                    'compare' => 'LIKE',
                ),
                array(
                    'key' => 'class_1_days',
                    'value' => array('Friday','Saturday')
                    'compare' => 'IN',
                )
            )

    );

Étant donné que vous avez des données sérialisées, cela va être difficile. Vous pouvez écrire un filtre pour posts_where mais je m'attendrais à ce que le résultat soit inefficace et sujet aux erreurs.

La bonne approche pour les cas comme celui-ci dans lesquels vous devez rechercher/filtrer/trier en fonction de certaines informations est, selon mon expérience, de ne pas stocker vos données sous la forme d'un tableau sérialisé. C'est tout simplement la mauvaise approche si vous avez besoin de telles requêtes.

Si je prenais en charge ce projet, je parcourrais les données à interroger de cette manière et réenregistrais chaque pièce dans une paire clé/valeur. Les pièces que vous n'interrogez pas peuvent rester sérialisées. Il n'y a pas de (bon) moyen de le faire dans MySQL avec les fonctions MySQL, que ce soit dans le cadre de la requête que vous tentez ou en tant que requête autonome. J'ai vu des tentatives de création d'une fonction MySQL "unserialize" mais je ne vois pas l'intérêt. Ré-enregistrer les données est la voie à suivre.

Il devrait être une requête assez simple pour obtenir toutes les données class_1_days. Bouclez ensuite dessus, sauvegardez les pièces que vous devez interroger sous forme de clés indépendantes et remettez le reste sous forme de données sérialisées.

2
s_ha_dum