Пользовательская таксономия и множественные условия запроса

Вопрос или проблема

У меня есть такой запрос

$query->set( 'tax_query', array(
                    'relation' => 'OR',
                    array(
                        'taxonomy' => 'location',
                         'operator' => 'IN',
                        'field' => 'slug',
                        'terms' => $availableRegions,
                    ),
                    array(
                        'taxonomy' => 'location',
                         'operator' => 'NOT IN',
                        'field' => 'slug',
                        'terms' => $notavailableRegions,
                    )
                ));

и он возвращает этот SQL-запрос

SELECT wp_posts.ID
FROM wp_posts 
INNER JOIN wp_term_relationships
ON (wp_posts.ID = wp_term_relationships.object_id) JOIN wp_icl_translations t
ON wp_posts.ID = t.element_id 
AND t.element_type IN ('bla') JOIN wp_icl_languages l
ON t.language_code=l.code
AND l.active=1
WHERE 1=1  


AND (
wp_term_relationships.term_taxonomy_id IN (200) 

OR wp_posts.ID NOT IN ( 
SELECT object_id 
FROM wp_term_relationships 
WHERE term_taxonomy_id IN (201,203,205,206) )
)

но что мне действительно нужно, так это вернуть этот SQL

SELECT wp_posts.ID
FROM wp_posts 
INNER JOIN wp_term_relationships
ON (wp_posts.ID = wp_term_relationships.object_id) JOIN wp_icl_translations t
ON wp_posts.ID = t.element_id 
AND t.element_type IN ('bla') JOIN wp_icl_languages l
ON t.language_code=l.code
AND l.active=1
WHERE 1=1  


AND (
wp_term_relationships.term_taxonomy_id IN (200) 
OR wp_term_relationships.term_taxonomy_id NOT IN (201,203,205,206) 

)

какие-нибудь предложения, чтобы спасти мой уикенд 😀

Допустим, у вас есть 5 экземпляров:
200, 201, 202, 203, 204

NOT IN {200, 201, 202} эквивалентно IN {203, 204} (все другие экземпляры).

Так что вам больше не нужен оператор IN, потому что его результаты уже включены из-за использования оператора NOT IN.

В вашем случае эта логика работает, предполагая, что у статьи нет нескольких местоположений.

$query->set('tax_query',

        array(
            array (
                'taxonomy' => 'location',
                'operator' => 'NOT IN',
                'field' => 'slug',
                'terms' => $notavailableRegions,
            )
        )
);

Ответ или решение

Конечно, давайте подробнее разберем вашу ситуацию с использованием пользовательской таксономии и многослойными условиями запроса.

Контекст и Проблема

Вы строите запрос на основе нескольких условия по пользовательской таксономии, что является распространенной задачей в WordPress. Ваш начальный запрос использует tax_query, чтобы определить, какие записи выбрать на основе таксономии "location", с использованием операторов IN и NOT IN. Однако генерация SQL-запроса происходит не так, как вы ожидали.

Анализ Исходного Запроса

Ваш текущий запрос выглядит так:

$query->set('tax_query', array(
    'relation' => 'OR',
    array(
        'taxonomy' => 'location',
        'operator' => 'IN',
        'field' => 'slug',
        'terms' => $availableRegions,
    ),
    array(
        'taxonomy' => 'location',
        'operator' => 'NOT IN',
        'field' => 'slug',
        'terms' => $notavailableRegions,
    )
));

Этот подход создает SQL-запрос, где условия IN и NOT IN лежат в разных подусловиях. Это не позволяет вам получить желаемую логику, где одно условие не зависит от другого. Использование OR здесь приводит к тому, что записи, соответствующие обоим условиям сначала смешиваются, а потом отфильтровываются.

Необходимое Решение

Чтобы добиться желаемого результата, вам нужно сделать следующее:

Логика Условия

Как вы отметили, NOT IN фактически освобождает вас от необходимости использовать оператор IN, если вы строите условия так, чтобы они были взаимоисключающими. Это возможно, если вы уверены, что записи не могут иметь несколько значений таксономии. В таком случае обработка будет выглядеть так:

$query->set('tax_query', array(
    'relation' => 'AND',
    array(
        'taxonomy' => 'location',
        'operator' => 'NOT IN',
        'field' => 'slug',
        'terms' => $notavailableRegions,
    ),
    array(
        'taxonomy' => 'location',
        'operator' => 'IN',
        'field' => 'slug',
        'terms' => $availableRegions,
    )
));

SQL-запрос

Теперь SQL-запрос должен выглядеть следующим образом:

SELECT wp_posts.ID
FROM wp_posts 
INNER JOIN wp_term_relationships
ON (wp_posts.ID = wp_term_relationships.object_id) 
JOIN wp_icl_translations t
ON wp_posts.ID = t.element_id 
AND t.element_type IN ('bla') 
JOIN wp_icl_languages l
ON t.language_code = l.code
AND l.active = 1
WHERE 1 = 1  
AND (
    wp_term_relationships.term_taxonomy_id NOT IN (201, 203, 205, 206)
    OR wp_term_relationships.term_taxonomy_id IN (200)
)

Заключение

Таким образом, предлагаемые изменения должны вернуть правильный SQL-запрос, соответствующий вашим требованиям. Во избежание возникновения проблем с производительностью, рекомендуется профилировать конечный запрос на больших объемах данных. Обращайте внимание на производительность и оптимизацию, чтобы ваш код был не только корректным, но и эффективным.

Если у вас есть дальнейшие вопросы, не стесняйтесь обращаться. Желаю успешной работы и приятного уикенда!

Оцените материал
Добавить комментарий

Капча загружается...