Вопрос или проблема
Я пытаюсь выполнить запрос к записям из базы данных WP с категорией uncategorised
, одновременно присоединяя таблицу мета данных записей, но у меня это не получается.
Я получаю пустой результат.
Вот мой запрос
SELECT * FROM wptests_posts wp
INNER JOIN wptests_postmeta wm ON (wm.`post_id` = wp.`ID`)
INNER JOIN wptests_term_relationships wtr ON (wp.`ID` = wtr.`object_id`)
INNER JOIN wptests_term_taxonomy wtt ON (wtr.`term_taxonomy_id` = wtt.`term_taxonomy_id`)
INNER JOIN wptests_terms wt ON (wt.`term_id` = wtt.`term_id`) AND
((wtt.`taxonomy` = 'category' AND wt.`slug` = 'uncategorized'))
Видимо, проблема в внутреннем соединении с postmeta на второй строке. Если я его убираю, я получаю ожидаемые результаты, но не получаю мета данные записей.
Любая помощь приветствуется
Это отлично сработало для меня. Включение postmeta может быть немного сложным. Без него я получил около 150 результатов. С ним — более 5000. Я никогда не получал пустой результат.
Поскольку postmeta может иметь от нуля до сотен элементов на запись, создается новая строка для каждого элемента postmeta с повторением информации о записи для каждой строки.
Поэтому я добавил GROUP BY wp.ID
, и это сломалось:
Ошибка запроса 1: Выражение #24 в списке SELECT не включено в предложение GROUP BY
и содержит неагрегированный столбец ‘local.wm.meta_id’, который не
функционально зависит от столбцов в GROUP BY; это
несовместимо с sql_mode=only_full_group_by
Это было главным образом потому, что колонка GROUP BY
(wp.ID
) должна быть в SELECT. Это все равно не дало бы вам postmeta. Поэтому без group by это работало, вам просто нужно было бы обработать это после получения результатов и затем объединить их.
Нет отличного способа получить все мета данные в одном запросе. Лучше указать то, что вам нужно, или использовать более одного запроса.
Одним из вариантов является приведенное ниже, но оно может привести к переполнению памяти на CONCAT()
операциях. У меня были проблемы с записями с большим количеством мета данных. Оно возвращает все мета ключи в одном столбце и все мета значения в столбце, которые могут быть просто разделены в цикле позже.
SELECT
wp.ID,
wp.*,
GROUP_CONCAT(wm.meta_key ORDER BY wm.meta_key DESC SEPARATOR '||') as meta_keys,
GROUP_CONCAT(wm.meta_value ORDER BY wm.meta_key DESC SEPARATOR '||') as meta_values
FROM
wptests_posts wp
INNER JOIN wptests_postmeta wm ON (wm.`post_id` = wp.`ID`) AND wm.meta_key NOT LIKE '\_%'
INNER JOIN wptests_term_relationships wtr ON (wp.`ID` = wtr.`object_id`)
INNER JOIN wptests_term_taxonomy wtt ON (wtr.`term_taxonomy_id` = wtt.`term_taxonomy_id`) AND (wtt.`taxonomy` = 'category')
INNER JOIN wptests_terms wt ON (wt.`term_id` = wtt.`term_id`) AND (wt.`slug` = 'uncategorised')
GROUP BY wp.ID
Что-то вроде:
function custom_separate_postmeta( $a ) {
$output = array_merge( $a, array_combine( explode('||', $a['meta_keys']), array_map('maybe_unserialize', explode('||', $a['meta_values'])) ) );
unset($output['meta_keys']);
unset($output['meta_values']);
return $output;
}
И вы можете запустить это на ваших результатах:
$posts = array_map( 'custom_separate_postmeta', $posts );
Просто несколько идей по этой проблеме..
Ответ или решение
Запрос к базе данных WordPress для выборки постов с определенной категорией и их метаданными является типичной задачей для разработчиков, которые стремятся извлечь данные напрямую с помощью MySQL. Рассмотрим, как выполнить такой запрос правильно и эффективно.
Проблема
Изначальный запрос, который вы используете, возвращает пустой результат, когда вы пытаетесь подключить таблицу метаданных постов (wptests_postmeta
). Без этой таблицы данные возвращаются корректно, но, конечно, вы теряете важные метаданные.
Анализ проблемы
-
Множественные метаданные: Таблица
postmeta
часто содержит множество записей для каждого поста, что создает дубликаты записей в результате JOIN операции. Это объясняет увеличение количества результатов, даже если данные по сути одинаковы. -
GROUP BY ограничение: Использование
GROUP BY wp.ID
вызывает проблему, так как MySQL требует, чтобы все избранные столбцы, которые не агрегированы, были включены в GROUP BY при наличии режимаONLY_FULL_GROUP_BY
.
Решение
Решим задачу оптимально используя метод агрегации для метаданных:
SELECT
wp.ID,
wp.post_title,
GROUP_CONCAT(wm.meta_key ORDER BY wm.meta_key DESC SEPARATOR '||') as meta_keys,
GROUP_CONCAT(wm.meta_value ORDER BY wm.meta_key DESC SEPARATOR '||') as meta_values
FROM
wptests_posts wp
INNER JOIN wptests_postmeta wm ON (wm.post_id = wp.ID) AND wm.meta_key NOT LIKE '\_%'
INNER JOIN wptests_term_relationships wtr ON (wp.ID = wtr.object_id)
INNER JOIN wptests_term_taxonomy wtt ON (wtr.term_taxonomy_id = wtt.term_taxonomy_id) AND wtt.taxonomy = 'category'
INNER JOIN wptests_terms wt ON (wt.term_id = wtt.term_id) AND wt.slug = 'uncategorised'
GROUP BY wp.ID
Обработка результатов
После выполнения запроса данные метаданных агрегируются в строках, разделенных ||
. Чтобы их использовать, создадим вспомогательную функцию на PHP:
function custom_separate_postmeta($a) {
$output = array_merge($a, array_combine(explode('||', $a['meta_keys']), array_map('maybe_unserialize', explode('||', $a['meta_values']))));
unset($output['meta_keys']);
unset($output['meta_values']);
return $output;
}
$posts = array_map('custom_separate_postmeta', $posts);
Вывод
Такой подход позволяет сократить количество повторяющихся записей и обрабатывать метаданные на уровне приложения. Это решение хотя и сложное в реализации, но предлагает оптимальный баланс между сложностью и результативностью. Важно также не забывать настройку виртуальной машины либо сервера для обработки больших объемов данных, так как использование функций агрегации может быть ресурсоемким.