Запрос всех записей, где мета-ключ не существует

12 янв. 2013 г., 18:48:33
Просмотры: 109K
Голосов: 70

Я пытаюсь составить запрос для получения всех записей, где определенный meta_key не существует, чтобы затем создать его.

У меня возникли проблемы с поиском этих записей, так как тестируемый запрос, похоже, не работает.

Вот код, который я использую для попытки получить эти записи:

$args = array(
   'posts_per_page' => 18,
   'cat'=>1955,
   'post_status'=>'publish',
   'meta_query' => array(
                  array(
                     'key' => 'colors',
                     'compare' => 'NOT EXISTS'
                  ),
   ));      

query_posts($args);

Это не возвращает ничего, если нет записей с ключом colors, но возвращает ids записей с ключом colors, когда этот ключ присутствует (противоположное тому, что мне нужно). Я пробовал использовать EXIST, но безуспешно.

Буду признателен, если кто-то подскажет правильный способ создания нужного мне запроса.

Спасибо!

7
Комментарии

Какую версию WordPress вы используете?

s_ha_dum s_ha_dum
12 янв. 2013 г. 19:10:08

Привет, извините за упущение. Я использую версию 3.5

JordanBel JordanBel
12 янв. 2013 г. 20:27:19

Похоже, что такой тип запроса (с compare установленным в NOT EXISTS) был добавлен в версии 3.5, так что он должен работать как есть, насколько я могу судить. Хотя это легко можно сделать через пользовательский SELECT запрос...

Tomas Buteler Tomas Buteler
12 янв. 2013 г. 22:00:37

Спасибо, попробую использовать select. Хотя сначала мне нужно разобраться, какие таблицы запрашивать и как правильно составить запрос :(

JordanBel JordanBel
12 янв. 2013 г. 23:08:34

Очень странно. Я не вижу проблемы в этом коде, а вы используете версию 3.5+, поэтому я и спросил. Вы проверяли базу данных, чтобы убедиться, что данные вставляются так, как вы ожидаете?

s_ha_dum s_ha_dum
13 янв. 2013 г. 19:07:02

Вы пробовали использовать 'EXISTS'? Вы упомянули 'EXIST', но, кажется, compare принимает только 'EXISTS' с буквой 'S' в конце.

mikegertrudes mikegertrudes
13 янв. 2013 г. 22:36:10

Привет, спасибо. К сожалению, EXISTS тоже не сработал. Думаю, я выберу вариант с запросом.

JordanBel JordanBel
14 янв. 2013 г. 03:01:41
Показать остальные 2 комментариев
Все ответы на вопрос 3
8
108

Я провел дополнительные тесты и, честно говоря, не вижу причин, почему это не должно работать (если только приведенный выше код не является фрагментом, а реальный код соответствует моим примерам ниже). Однако я обнаружил пару моментов, которые могут направить вас в правильное русло.

1) Сам по себе этот meta_query эквивалентен условию "colors IS NULL", т.е. он вернет записи, у которых этот ключ не установлен в таблице postmeta. Это показано выше, и это должно было работать.

'meta_query' => array(
    array(
     'key' => 'colors',
     'compare' => 'NOT EXISTS' // это должно работать...
    ),
)

2) До WordPress 3.9 установка индекса 'relation' в значение 'OR' меняет это условие. Оно возвращает противоположный результат. Не спрашивайте меня почему. Это особенно важно при выполнении нескольких meta-запросов. Это означает, что изначально невозможно сделать запрос для записей, у которых ключ 'colors' установлен в значение 'blue' (или любое другое) или не установлен вообще. Запрос ниже проигнорирует первое условие и вернет только те записи, которые соответствуют второму условию.

'meta_query' => array(
   'relation' => 'OR',
    array(
     'key' => 'colors',
     'compare' => 'NOT EXISTS' // не работает
    ),
    array(
     'key' => 'colors',
     'value' => 'blue'
    )
)

3) Однако мы можем обмануть WordPress, заставив его использовать первое условие, если мы установим 'value'. Это значение не должно быть релевантным (оно игнорируется, насколько я знаю), но оно должно быть установлено, чтобы условие NOT EXISTS имело какой-либо эффект.

'meta_query' => array(
   'relation' => 'OR',
    array(
     'key' => 'colors',
     'compare' => 'NOT EXISTS', // работает!
     'value' => '' // Это игнорируется, но необходимо...
    ),
    array(
     'key' => 'colors',
     'value' => 'blue'
    )
)

Это было актуально до WordPress 3.9. Если вы все еще используете более старую версию, это рабочее решение.

16 янв. 2013 г. 17:05:16
Комментарии

Спасибо! И извините за задержку. В итоге я использовал запрос, но в ближайшие часы протестирую ваше решение, чтобы можно было вернуться к нему. Если это сработает, мы сможем помочь и другим. Дам знать, как только проверю. Ещё раз спасибо!

JordanBel JordanBel
17 янв. 2013 г. 03:49:32

Хорошо написано и подтверждено, что добавление пустого значения возвращает ожидаемые результаты. Скорее всего, это непреднамеренно, возможно стоит проверить trac.wordpress.org на наличие уже созданного тикета. Если его нет, то ошибка воспроизводима.

Taylor Dewey Taylor Dewey
6 мар. 2013 г. 21:22:07

Спасибо за отличное объяснение и решение, как обойти WP :) Потребовалось время, чтобы добраться сюда - теперь хочется поставить плюс хотя бы 10 раз (если бы только можно было ;))

lorem monkey lorem monkey
21 мар. 2013 г. 16:18:41

Если я использую сравнение EXISTS, к сожалению, значение не игнорируется в новых версиях WP (проверено в 4.2.2)

Igor Jerosimić Igor Jerosimić
1 июл. 2015 г. 13:08:45

Обратите внимание на orderby meta_key, который также может быть в вашем запросе! Wordpress жестко прописывает WHERE meta_key = value для сортировки по мета-полю!

Chizzle Chizzle
8 апр. 2016 г. 06:12:57

"Баг" с EXISTS и NOT EXISTS, который требовал указания значения, был исправлен в WP 3.9

trex005 trex005
15 апр. 2016 г. 10:42:22

trex005 прав: "(Примечание: Из-за бага #23268, значение обязательно для корректной работы сравнений NOT EXISTS до версии 3.9. Вы должны указать какую-либо строку для параметра value. Пустая строка или NULL НЕ сработают. Однако, любая другая строка подойдет и НЕ появится в вашем SQL при использовании NOT EXISTS. Нужно вдохновение? Как насчет 'bug #23268'.)"

jave.web jave.web
29 апр. 2017 г. 22:56:11

Комбинация 'OR', показанная выше в пункте 3), также работает для меня, но она очень неэффективна и приводит к сильной нагрузке с временем отклика более 30 секунд. (используется Woocommerce с более чем 9000 товаров)

Andy Tschiersch Andy Tschiersch
6 окт. 2021 г. 14:22:12
Показать остальные 3 комментариев
0
20

Используя пользовательский запрос, у меня сработало следующее:

SELECT * FROM wp_posts as posts
            WHERE   posts.post_type     = 'post'
            AND NOT EXISTS (
              SELECT * FROM `wp_postmeta`
               WHERE `wp_postmeta`.`meta_key` = "your_meta_key"
                AND `wp_postmeta`.`post_id`=posts.ID
            ) 
9 янв. 2015 г. 23:50:35
0

Добавление отношения делает запрос рабочим, даже если есть только одно условие

'meta_query' => array(
   'relation' => 'OR',
    array(
     'key' => 'colors',
     'compare' => 'NOT EXISTS' 
    )
)
9 янв. 2020 г. 12:49:34