Utilizarea condițiilor OR în meta_query pentru argumentul query_posts

24 iun. 2013, 18:36:37
Vizualizări: 39.7K
Voturi: 9

Am căutat peste tot dar nu am reușit să găsesc nimic relevant.

Încerc să filtrez niște rezultate și când creez un array de argumente ca acesta și îl transmit către query_posts am observat că SQL-ul generat folosește AND în loc de OR pentru valoarea 'class_1_days'. Aș dori să transform asta într-un OR. Cum aș putea face acest lucru? (Folosesc LIKE deoarece datele sunt serializate, altfel aș fi încercat un "IN" și aș fi transmis un array. Care este modalitatea corectă de a face acest lucru?)

$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' => 'Vineri',
                        'compare' => 'LIKE',
                    ),
                    array(
                        'key' => 'class_1_days',
                        'value' => 'Sâmbătă',
                        'compare' => 'LIKE',
                    ),
                )

        );

Acesta este SQL-ul relevant care este generat unde am observat AND-ul

[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 '%Vineri%')
AND  (mt2.meta_key = 'class_1_days' AND CAST(mt2.meta_value AS CHAR) LIKE '%Sâmbătă%') ) GROUP BY wp_posts.ID ORDER BY wp_posts.post_date DESC LIMIT 0, 5
0
Toate răspunsurile la întrebare 2
9
14

Folosește 'relation' => 'OR' ca în exemplul din Codex de mai jos:

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

Aceasta va genera o condiție OR între toate blocurile meta_query. Dacă ai nevoie de ceva de genul WHERE "instructor" = 1128 AND (class_1_days = "value1" OR class_1_days = "value2"), atunci ceva de genul acesta ar funcționa dacă datele tale nu ar fi serializate.

$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',
                )
            )

    );

Având în vedere că ai date serializate, acest lucru va fi dificil. Ai putea scrie un filtru pentru posts_where, dar mă aștept ca rezultatul să fie ineficient și predispus la erori.

Abordarea corectă pentru cazuri de genul acesta, în care trebuie să cauți/filtrezi/sortezi după o anumită informație, este, în experiența mea, să nu stochezi datele ca un array serializat în primul rând. Aceasta este pur și simplu abordarea greșită dacă ai nevoie de astfel de interogări.

Dacă aș prelua acest proiect, aș parcurge datele care trebuie interogate în acest fel și aș salva fiecare parte ca o pereche cheie/valoare. Părțile pe care nu le interoghezi pot rămâne serializate. Nu există nicio modalitate (bună) de a face acest lucru în MySQL cu funcții MySQL, fie ca parte a interogării pe care o încerci, fie ca o interogare separată. Am văzut încercări de a crea o funcție MySQL "unserialize", dar nu văd rostul. Reserializarea datelor este soluția corectă.

Ar trebui să fie o interogare destul de simplă pentru a obține toate datele class_1_days. Apoi parcurge-le și salvează părțile de care ai nevoie pentru interogare ca chei independente și pune restul înapoi ca date serializate.

24 iun. 2013 18:50:37
Comentarii

Mulțumesc mult pentru răspuns. Există o modalitate prin care pot face un AND sau OR? Încerc să păstrez partea de instructor. Exemplul tău le face pe toate OR. Am nevoie doar ca partea class_1_days să fie un OR. Similar cu dacă aș avea 'value' => array(bla,bla,bla), 'compare' => IN

Practic unde Instructor = 'bla' ȘI value IN (bla,bla,bla)

Devario Johnson Devario Johnson
24 iun. 2013 19:06:52

Mulțumesc @S_ha_dam. Există o modalitate prin care pot deserializa baza de date. Acesta este un proiect pe care l-am preluat, așa că nu știu exact ce efect va avea. Am văzut un link către o aplicație care făcea exact asta, dar linkul era stricat.

Devario Johnson Devario Johnson
24 iun. 2013 19:09:55

Mulțumesc, dar simpla re-salvare nu va funcționa - acesta este un mediu live unde aceste date sunt salvate constant, iar class_1_data este doar o parte din ecuație. Există multiple elemente: class_0_data, class_2_data, etc., și acestea sunt adăugate de utilizatori. Cred că cea mai bună abordare ar fi să mă întorc și să găsesc o modalitate de a reinstala modulul și să-l configurez astfel încât să nu salveze serializat (dacă reușesc să aflu cum) și să merg mai departe X-( ... Nu am menționat partea cu celelalte clase pentru că am crezut că o să pot să o rezolv singur.

Devario Johnson Devario Johnson
24 iun. 2013 19:23:08

Cu siguranță va trebui să refactorizezi funcția "save", dar va fi necesar să salvezi din nou și datele existente, altfel vei ajunge cu un amestec ciudat între serializate și neserializate. Obține codul funcțional pe un server de dezvoltare, apoi pune cel live în modul de întreținere pentru douăzeci de minute într-un moment al zilei cu trafic scăzut.

s_ha_dum s_ha_dum
24 iun. 2013 19:27:37

Oh da, cu siguranță va trebui să modific datele curente!

asta e nasol. Credeam că va fi o soluție ușoară, vai!

Devario Johnson Devario Johnson
24 iun. 2013 19:30:01

stai...dar ce zici de asta...există vreo modalitate să adaug DUPĂ acest filtru încă un filtru după instructor?

Sau chiar să obțin înapoi array-ul php direct pe care îl folosește WordPress și să-l editez?

Devario Johnson Devario Johnson
24 iun. 2013 19:30:59

Nu sunt sigur că am înțeles ultima întrebare, dar prin filtre poți modifica interogarea să fie aproape orice dorești. Prin "atașarea" a ceva, însă, cred că nu vei ajunge la o interogare eficientă.

s_ha_dum s_ha_dum
24 iun. 2013 19:35:20

Uh, de exemplu, în PHP ai avea array-ul tău real ca fiind classes[1][bla], classes[2][bla] etc. Dacă aș ști cum se numește acel array, aș putea face o căutare în array și regex și să-l filtrez singur după ce am obținut rezultatele dorite din instrucțiunea OR pe care ai furnizat-o mai devreme.

Devario Johnson Devario Johnson
24 iun. 2013 19:39:24

Da, este posibil, dar ar trebui să obții toate datele și apoi să le sortezi.

s_ha_dum s_ha_dum
24 iun. 2013 19:40:22
Arată celelalte 4 comentarii
1

Conform WordPress codex, tablourile imbricate pot fi utilizate pentru a construi interogări complexe. În exemplul tău ai nevoie de ceva de genul:

$args = array(
    'taxonomy' => 'courses', 
    'term' => 'drawing', 
    'post_type' => 'school', 
    'paged' => $paged,
    'meta_query' =>
        array(
           'relation' => 'AND', // relație implicită
            array(
                'key' => 'instructor',
                'value' => '1128',
                'compare' => 'LIKE', // comparare cu LIKE
            ),
            array(
                'relation' => 'OR',
                array(
                    'key' => 'class_1_days',
                    'value' => 'Friday', // Vineri
                    'compare' => 'LIKE',
                ),
                array(
                    'key' => 'class_1_days',
                    'value' => 'Saturday', // Sâmbătă
                    'compare' => 'LIKE',
                ),
            )
        )
); 
27 iul. 2020 00:26:55
Comentarii

A trebuit să caut asta. Am o interogare complexă care se referă la acest lucru. Ai primit atât de multe voturi încât cred că voi pune o nouă întrebare pe baza acesteia. Sunt foarte interesat să văd cum abordează comunitatea acest tip de problemă în prezent, să fiu sincer.

Nathan Powell Nathan Powell
31 ian. 2025 03:11:52