使用 IN 根据多个元键/值对获取 WP 帖子

发布于 2025-01-11 05:30:53 字数 2180 浏览 0 评论 0原文

我在格式化查询以根据两个元值的值从数据库获取帖子列表时遇到一些问题。我使用的是 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
    )
);

上述查询应获取所有帖子,其中:

  • 帖子在 wp_posts 中的 post_typebook
  • meta_key 为 book_genre > 且 wp_postmetafiction 的 meta_value 的
  • meta_key 为 category,meta_value 为 239, wp_postmeta 中的 440
  • 将结果限制为 xyz
  • 偏移结果 xyz

但是,上述查询返回值 null< /code> 如果我 var_dump( $posts ); 到页面上,所以我想这部分可能会导致与第一个元键/值规则发生某种冲突?

如果我删除查询的 IN 部分,它会按预期获得所有内容,减去我想要的类别的过滤。类别 id 是一个 id 数组,使用 PHP 的 implode() 将其转换为逗号分隔的字符串。

例如:

  • Post 1 的 post_type 为 book,元键/值对为 book_genrefiction< /code> 并具有“category”和 440 元键/值对,因此使用上述查询应包含

  • Post 2 的 post_type 为 book,元键/值对为 book_genrefiction并且具有“category”和 323 的元键/值对,因此不应使用上述查询包含在内。

I'm having some trouble formatting my query to fetch a list of posts from the database based on the value of two meta values. I'm using WordPress 4.9.4 and I need to use $wpdb->get_results() and not a normal get_posts() function call with arguments.

Here is what I have so far, but if I try and include the IN part in the MySQL query, it doesn't return anything but it should return at least one post.

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
    )
);

The above query should get all posts where:

  • the post has a post_type of book in wp_posts
  • has a meta_key of book_genre and meta_value of fiction in wp_postmeta
  • has a meta_key of category and meta_value of 239, 440 in wp_postmeta
  • limit results to xyz
  • offset results of xyz

However, the above query returns a value of null if I var_dump( $posts ); onto the page, so I imagine that the in part is causing some sort of conflict with the first meta key/value rule, perhaps?

If I remove the IN part of the query it gets everything as expected minus the filtering of the categories of course that I'd like. The category ids are an array of ids that are converted into a comma-separated string using PHP's implode().

For example:

  • Post 1 has a post_type of book, has a meta key/value pair of book_genre and fiction and has a meta key/value pair of 'category' and 440 so should be included using the above query.

  • Post 2 has a post_type of book, has a meta key/value pair of book_genre and fiction and has a meta key/value pair of 'category' and 323 so should not be included using the above query.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

羁绊已千年 2025-01-18 05:30:53

您需要加入 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

这里有两个 postmeta 表的连接副本,别名为 pm1pm2(因为它们不能同时称为 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 来完成此操作。

You need to join the post_meta table twice. Here's some database theory.

When you join tables, in theory a temporary table contains all of the items from the first table combined with all of the items from the second table is created and filtered. So if, for example, you have just 1 meta item per post, and you have 3 posts then you have

+-------+----------+
|post_id|post_title|
+-------+----------+
|   1   | 'Post 1' |
|   2   | 'Post 2' |
|   3   | 'Post 3' |
+-------+----------+

and

+-------+----------+----------+------------+
|meta_id| post_id  | meta_key | meta_value |
+-------+----------+----------+------------+
|   10  | 1        |  k1      | v1         |
|   11  | 2        |  k1      | v2         |
|   12  | 3        |  k1      | v3         |
+-------+----------+----------+------------+

And the "theoretical" temporary joined table is:

+---------+------------+----------+----------+-----------+-------------+
|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          |
+---------+------------+----------+----------+-----------+-------------+

You then say: WHERE p.id = pm.post_id

and this filters the temporary table to be:

+---------+------------+----------+----------+-----------+-------------+
|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          |
+---------+------------+----------+----------+-----------+-------------+

So you only have one row for each post + meta value. Your query is asking for rows that have both meta_key = category and meta_key = book_genre` which don't exist.

So you need a table that joins the postmeta table in TWICE.

You can do this by aliasing the table as you join them. Forgive me for simplifying:

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

Here you have two joined copies of the postmeta table aliased to pm1 and pm2 (as they can't BOTH be called wp_postmeta in the query.

You can then ask for:

AND pm1.meta_key = 'category'
AND pm1.meta_value = X
AND pm2.meta_key = 'book_genre'
AND pm2.meta_key IN (123,456)

Hopefully you can stitch together the rest from that.

I also think you can do this with WP_Query if you want to go that route.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文