Вопрос или проблема
У меня есть такой запрос
$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-запрос, соответствующий вашим требованиям. Во избежание возникновения проблем с производительностью, рекомендуется профилировать конечный запрос на больших объемах данных. Обращайте внимание на производительность и оптимизацию, чтобы ваш код был не только корректным, но и эффективным.
Если у вас есть дальнейшие вопросы, не стесняйтесь обращаться. Желаю успешной работы и приятного уикенда!