我在格式化查询时遇到一些问题,根据两个元值的值从数据库中获取帖子列表。我正在使用WordPress 4.9.4,我需要使用$wpdb->get_results()
和不正常get_posts()
函数调用参数。
这是我到目前为止所做的,但如果我尝试在MySQL查询中包含IN
部分,它不会返回任何内容,但它应该返回至少一个帖子。
global $wpdb;
$posts = $wpdb->get_results(
$wpdb->prepare(
'SELECT ' . $wpdb->prefix . 'posts.*, ' . $wpdb->prefix . 'postmeta.* FROM ' . $wpdb->prefix . 'posts, ' . $wpdb->prefix . 'postmeta WHERE ' . $wpdb->prefix . 'posts.post_type = %s AND ' . $wpdb->prefix . 'postmeta.post_id = ' . $wpdb->prefix . 'posts.ID AND (' . $wpdb->prefix . 'postmeta.meta_key = %s AND ' . $wpdb->prefix . 'postmeta.meta_value = %s) AND (' . $wpdb->prefix . 'postmeta.meta_key = %s AND ' . $wpdb->prefix . 'postmeta.meta_value IN (%s)) ORDER BY ' . $wpdb->prefix . 'posts.post_title ASC LIMIT %d OFFSET %d',
'book',
'book_genre',
$genre,
'category',
'239, 440',
$limit,
$offset
)
);
以上查询应获取所有帖子:
post_type
book
wp_posts
book_genre
fiction
和meta_value wp_postmeta
的meta_key
category
239, 440
和meta_value wp_postmeta
的meta_key
xyz
xyz
但是,如果I null
在页面上,上面的查询会返回var_dump( $posts );
的值,所以我想这部分是与第一个元键/值规则发生某种冲突,也许?
如果我删除查询的IN
部分,它会按预期获得所有内容,减去我想要的类别的过滤。类别ID是一组id,使用PHP implode()
转换为逗号分隔的字符串。
例如:
帖子1
的post_type为book
,其元键/值对为book_genre
和fiction
,并且具有元键/值对“类别”和440
因此 应 使用上述查询。
帖子2
的post_type为book
,其元键/值对为book_genre
和fiction
,并且具有元键/值对“类别”和323
因此 不应 使用上述查询。
答案 0 :(得分:1)
您需要两次加入post_meta
表。这是一些数据库理论。
当您连接表时,理论上临时表包含第一个表中的所有项目以及第二个表中的所有项目的创建和过滤。因此,例如,如果每个帖子只有1个元项目,并且您有3个帖子,那么您有
+-------+----------+
|post_id|post_title|
+-------+----------+
| 1 | 'Post 1' |
| 2 | 'Post 2' |
| 3 | 'Post 3' |
+-------+----------+
和
+-------+----------+----------+------------+
|meta_id| post_id | meta_key | meta_value |
+-------+----------+----------+------------+
| 10 | 1 | k1 | v1 |
| 11 | 2 | k1 | v2 |
| 12 | 3 | k1 | v3 |
+-------+----------+----------+------------+
"理论"临时联合表是:
+---------+------------+----------+----------+-----------+-------------+
|p.post_id|p.post_title|pm.meta_id|pm.post_id|pm.meta_key|pm.meta_value|
+---------+------------+----------+----------+-----------+-------------+
| 1 | 'Post 1' | 10 | 1 | k1 | v1 |
| 1 | 'Post 1' | 11 | 2 | k1 | v2 |
| 1 | 'Post 1' | 12 | 3 | k1 | v3 |
| 2 | 'Post 2' | 10 | 1 | k1 | v1 |
| 2 | 'Post 2' | 11 | 2 | k1 | v2 |
| 2 | 'Post 2' | 12 | 3 | k1 | v3 |
| 3 | 'Post 3' | 10 | 1 | k1 | v1 |
| 3 | 'Post 3' | 11 | 2 | k1 | v2 |
| 3 | 'Post 3' | 12 | 3 | k1 | v3 |
+---------+------------+----------+----------+-----------+-------------+
然后你说:WHERE p.id = pm.post_id
并将临时表过滤为:
+---------+------------+----------+----------+-----------+-------------+
|p.post_id|p.post_title|pm.meta_id|pm.post_id|pm.meta_key|pm.meta_value|
+---------+------------+----------+----------+-----------+-------------+
| 1 | 'Post 1' | 10 | 1 | k1 | v1 |
| 2 | 'Post 2' | 11 | 2 | k1 | v2 |
| 3 | 'Post 3' | 12 | 3 | k1 | v3 |
+---------+------------+----------+----------+-----------+-------------+
因此,每个帖子+元值只有一行。您的查询要求同时存在meta_key = category
和meta_key = book_genre`的行。
所以你需要一个在TWICE中加入postmeta
表的表。
您可以在加入表时对表进行别名来执行此操作。原谅我简化:
SELECT wp_posts.*, pm1.*, pm2.*
FROM
wp_posts
wp_postmeta as pm1
wp_postmeta as pm2
WHERE pm1.post_id = wp_posts.ID
AND pm2.post_id = wp_posts.ID
AND ...etc
在这里,您有两个已归结为pm1
和pm2
的postmeta表的联合副本(因为它们在查询中无法被称为wp_postmeta
。
然后你可以要求:
AND pm1.meta_key = 'category'
AND pm1.meta_value = X
AND pm2.meta_key = 'book_genre'
AND pm2.meta_key IN (123,456)
希望你可以将其余部分拼接在一起。
如果你想走这条路,我也认为你可以用WP_Query做到这一点。