1

好的,我已经在这个逻辑上持续了几个星期,但我还没有生产出任何可行的东西。

我正在使用 Wordpress,因此在运行查询之前将其保存为字符串(其中包含 PHP)

如果您查看http://www.libertyguide.com/jobs,您会看到一个过滤器。我想做的是AND在这三个“类别”之间使用OR过滤,但在两者之间使用过滤。

例如:

如果我选择Academia,Law,Policy, Full-time,Part-time, Early-Career,我希望得到与此过滤逻辑匹配的帖子:

帖子有(academia OR law OR policy) AND (full-time OR part-time) AND (early-career)

所以本质上我想抓住与学术界、法律或政策相匹配的职位,然后用全职或兼职过滤掉,最后检查它是否有早期职业。

这是我使用上述示例运行的查询示例:

SELECT * FROM $wpdb->posts
LEFT JOIN $wpdb->postmeta ON($wpdb->posts.ID = $wpdb->postmeta.post_id)
LEFT JOIN $wpdb->term_relationships ON($wpdb->posts.ID = $wpdb->term_relationships.object_id)
LEFT JOIN $wpdb->term_taxonomy ON($wpdb->term_relationships.term_taxonomy_id = $wpdb->term_taxonomy.term_taxonomy_id)
LEFT JOIN $wpdb->terms ON($wpdb->terms.term_id = $wpdb->term_taxonomy.term_id)
WHERE 
    wp_term_taxonomy.term_id IN (SELECT term_id FROM wp_terms 
        WHERE slug='academia' OR slug='law' OR slug='policy') AND
    wp_term_taxonomy.term_id IN (SELECT term_id FROM wp_terms 
        WHERE slug='full-time' OR slug='part-time') AND
    wp_term_taxonomy.term_id IN (SELECT term_id FROM wp_terms 
        WHERE slug='early-career') AND... //Rest of query/irrelevant

这没有产生任何结果。我也尝试过这样的查询(前 5 行被省略,因为它们与上面的示例相同):

WHERE
    wp_term.slug IN ('academia','law','policy') AND
    wp_term.slug IN ('full-time','part-time') AND
    wp_term.slug IN ('early-career') AND ... //Rest of query

仅当一个“类别”已选择项目时才返回结果。它不适用于跨类别。我仍然认为我的查询略有错误。我之前得到了一些解决方案(这两个都是我认为最接近我的解决方案),但它们都有漏洞。

请不要让我使用HAVING COUNT,因为在这种情况下,我不妨把整个东西做成一个AND过滤器,这不是我想要的。

任何帮助将不胜感激,如果有效,我不介意想办法弥补麻烦。

谢谢!

4

3 回答 3

4

仅使用 WHERE 子句,我们可以看到一些问题:

WHERE wp_term_taxonomy.term_id IN (SELECT term_id FROM wp_terms 
                                    WHERE slug='academia' OR slug='law' OR slug='policy')
  AND wp_term_taxonomy.term_id IN (SELECT term_id FROM wp_terms 
                                    WHERE slug='full-time' OR slug='part-time')
  AND wp_term_taxonomy.term_id IN (SELECT term_id FROM wp_terms 
                                    WHERE slug='early-career')

在这里,我们有单列 ( wp_term_taxonomy.term_id),它必须与学术、法律或政策之一的术语 ID 同时相同(可能是 3 个不同的值),并且与全职或兼职之一的术语 ID 相同(可能是 2 个不同的值,并且与之前的 3 个值中的每一个都不同)并且也与 Early-Career 的术语 ID 相同(一个值,但与之前的 5 个值不同。因此,单个术语 ID 必须一次是 3 个不同的值,它无法管理它。

您可能需要wp_term_taxonomy使用 3 个不同的别名多次加入该表。

WHERE wtt1.term_id IN (SELECT term_id FROM wp_terms 
                        WHERE slug='academia' OR slug='law' OR slug='policy')
  AND wtt2.term_id IN (SELECT term_id FROM wp_terms 
                        WHERE slug='full-time' OR slug='part-time')
  AND wtt3.term_id IN (SELECT term_id FROM wp_terms 
                        WHERE slug='early-career')

我使用的 3 个别名是wtt1,wtt2wtt3. 它们将列在 JOIN 条件中。


让我们看一下选择列表和 FROM 子句

SELECT * FROM $wpdb->posts
LEFT JOIN $wpdb->postmeta ON($wpdb->posts.ID = $wpdb->postmeta.post_id)
LEFT JOIN $wpdb->term_relationships ON($wpdb->posts.ID = $wpdb->term_relationships.object_id)
LEFT JOIN $wpdb->term_taxonomy ON($wpdb->term_relationships.term_taxonomy_id = $wpdb->term_taxonomy.term_taxonomy_id)
LEFT JOIN $wpdb->terms ON($wpdb->terms.term_id = $wpdb->term_taxonomy.term_id)

现在让我们解开一些 PHP 材料,留下常规 SQL:

SELECT *
  FROM wp_posts                   AS p
  LEFT JOIN wp_postmeta           AS pm ON p.ID = pm.post_id
  LEFT JOIN wp_term_relationships AS tr ON p.ID = tr.object_id
  LEFT JOIN wp_term_taxonomy      AS tt ON tr.term_taxonomy_id = tt.term_taxonomy_id
  LEFT JOIN wp_terms              AS tm ON tm.term_id = tt.term_id

您可能不希望这里有任何左连接;您不想看到不符合条件的帖子,但使用 LEFT JOIN 将意味着在这一部分中选择了许多帖子(尽管所有行随后都被已经讨论过的损坏的 WHERE 条件丢弃)。

一个帖子可能有多个术语关系条目。我们想要一个至少包含三个任期关系条目的帖子:一个用于学术界/法律/政策三人组,一个用于全职/兼职二人组,以及早期职业。

SELECT *
  FROM wp_posts    AS p
  JOIN wp_postmeta AS pm ON p.ID = pm.Post_ID
  JOIN (SELECT t1.Object_ID
          FROM wp_term_relationships AS tr
          JOIN wp_term_taxonomy      AS tt ON tr.term_taxonomy_id = tt.term_taxonomy_id
          JOIN wp_terms              AS tm ON tm.term_id = tt.term_id
         WHERE tm.slug IN ('academia', 'law', 'policy')
       ) AS t1 ON p.ID = t1.Object_ID
  JOIN (SELECT t1.Object_ID
          FROM wp_term_relationships AS tr
          JOIN wp_term_taxonomy      AS tt ON tr.term_taxonomy_id = tt.term_taxonomy_id
          JOIN wp_terms              AS tm ON tm.term_id = tt.term_id
         WHERE tm.slug IN ('full-time', 'part-time')
       ) AS t2 ON p.ID = t2.Object_ID
  JOIN (SELECT t1.Object_ID
          FROM wp_term_relationships AS tr
          JOIN wp_term_taxonomy      AS tt ON tr.term_taxonomy_id = tt.term_taxonomy_id
          JOIN wp_terms              AS tm ON tm.term_id = tt.term_id
         WHERE tm.slug = 'early-career')
       ) AS t3 ON p.ID = t3.Object_ID

我认为这可能会奏效——但现在已经很晚了,我可能会完全脱离困境。这当然不是一个简单的查询。


假设我的基本 SQL 是正确的,您只需将表名替换为 PHP 表示法即可:

SELECT *
  FROM $wpdb->posts    AS p
  JOIN $wpdb->postmeta AS pm ON p.ID = pm.Post_ID
  JOIN (SELECT t1.Object_ID
          FROM $wpdb->term_relationships AS tr
          JOIN $wpdb->term_taxonomy      AS tt ON tr.term_taxonomy_id = tt.term_taxonomy_id
          JOIN $wpdb->terms              AS tm ON tm.term_id = tt.term_id
         WHERE tm.slug IN ('academia', 'law', 'policy')
       ) AS t1 ON p.ID = t1.Object_ID
  JOIN (SELECT t1.Object_ID
          FROM $wpdb->term_relationships AS tr
          JOIN $wpdb->term_taxonomy      AS tt ON tr.term_taxonomy_id = tt.term_taxonomy_id
          JOIN $wpdb->terms              AS tm ON tm.term_id = tt.term_id
         WHERE tm.slug IN ('full-time', 'part-time')
       ) AS t2 ON p.ID = t2.Object_ID
  JOIN (SELECT t1.Object_ID
          FROM $wpdb->term_relationships AS tr
          JOIN $wpdb->term_taxonomy      AS tt ON tr.term_taxonomy_id = tt.term_taxonomy_id
          JOIN $wpdb->terms              AS tm ON tm.term_id = tt.term_id
         WHERE tm.slug = 'early-career')
       ) AS t3 ON p.ID = t3.Object_ID

您没有说正在使用哪个 DBMS,但它很可能是 MySQL。如果您使用的是 Oracle,则必须将 AS 排除在表别名之外。标准 SQL 和大多数其他 SQL DBMS 都可以使用 AS 作为表别名。请注意$wpdb->符号的使用如何受到表别名的限制;它使代码更容易阅读(尽管它仍然不容易阅读)。


错误修复和问题解决

未经测试的代码通常有错误;这与任何其他未经测试的代码没有什么不同。

第一个测试步骤是单独运行 FROM 子句中的子查询。这立即表明他们不应该引用t1.Object_IDtr.Object_ID在每种情况下都应该如此。在“早期职业”之后还有一个无关紧要的右括号。一旦我有一个可以运行(子)查询的测试数据库,这些错误就很容易被发现。

SELECT *
  FROM wp_posts    AS p
  JOIN wp_postmeta AS pm ON p.ID = pm.Post_ID
  JOIN (SELECT tr.Object_ID
          FROM wp_term_relationships AS tr
          JOIN wp_term_taxonomy      AS tt ON tr.term_taxonomy_id = tt.term_taxonomy_id
          JOIN wp_terms              AS tm ON tm.term_id = tt.term_id
         WHERE tm.slug IN ('academia', 'law', 'policy')
       ) AS t1 ON p.ID = t1.Object_ID
  JOIN (SELECT tr.Object_ID
          FROM wp_term_relationships AS tr
          JOIN wp_term_taxonomy      AS tt ON tr.term_taxonomy_id = tt.term_taxonomy_id
          JOIN wp_terms              AS tm ON tm.term_id = tt.term_id
         WHERE tm.slug IN ('full-time', 'part-time')
       ) AS t2 ON p.ID = t2.Object_ID
  JOIN (SELECT tr.Object_ID
          FROM wp_term_relationships AS tr
          JOIN wp_term_taxonomy      AS tt ON tr.term_taxonomy_id = tt.term_taxonomy_id
          JOIN wp_terms              AS tm ON tm.term_id = tt.term_id
         WHERE tm.slug = 'early-career'
       ) AS t3 ON p.ID = t3.Object_ID

通过这些修复,查询运行并生成了数据行。您可能会合理地决定您想要结果中的三个子查询中的 slug。您将子查询更改为 return tr.Object_ID, tm.slug。例如,查询的这个变体:

SELECT p.ID, t1.slug_1, t2.slug_2, t3.slug_3, pm.meta_key
      FROM wp_posts    AS p
      JOIN wp_postmeta AS pm ON p.ID = pm.Post_ID
      JOIN (SELECT tr.Object_ID, tm.slug AS slug_1
              FROM wp_term_relationships AS tr
              JOIN wp_term_taxonomy      AS tt ON tr.term_taxonomy_id = tt.term_taxonomy_id
              JOIN wp_terms              AS tm ON tm.term_id = tt.term_id
             WHERE tm.slug IN ('academia', 'law', 'policy')
           ) AS t1 ON p.ID = t1.Object_ID
      JOIN (SELECT tr.Object_ID, tm.slug AS slug_2
              FROM wp_term_relationships AS tr
              JOIN wp_term_taxonomy      AS tt ON tr.term_taxonomy_id = tt.term_taxonomy_id
              JOIN wp_terms              AS tm ON tm.term_id = tt.term_id
             WHERE tm.slug IN ('full-time', 'part-time')
           ) AS t2 ON p.ID = t2.Object_ID
      JOIN (SELECT tr.Object_ID, tm.slug AS slug_3
              FROM wp_term_relationships AS tr
              JOIN wp_term_taxonomy      AS tt ON tr.term_taxonomy_id = tt.term_taxonomy_id
              JOIN wp_terms              AS tm ON tm.term_id = tt.term_id
             WHERE tm.slug = 'early-career'
           ) AS t3 ON p.ID = t3.Object_ID;

在一些测试数据上产生了以下结果:

1575  policy  full-time  early-career  date_legible
1575  policy  full-time  early-career  date_timestamp
1575  policy  full-time  early-career  longitude
1575  policy  full-time  early-career  date_normal
1575  policy  full-time  early-career  url
1575  policy  full-time  early-career  _su_rich_snippet_type
1575  policy  full-time  early-career  _edit_last
1575  policy  full-time  early-career  expiration-date
1575  policy  full-time  early-career  organization
1575  policy  full-time  early-career  latitude
1575  policy  full-time  early-career  location
1575  policy  full-time  early-career  _edit_lock

这表明至少有一篇文章 (ID = 1575) 具有您需要的三个特征,但这也表明您将不得不更巧妙地处理 PostMeta 数据。结果表明 PostMeta 是一个 EAV(实体-属性-值)模型。这将需要仔细处理以提取给定帖子的有用信息(例如纬度和经度)。实际上,您将需要一个(可能是外部的)连接用于您想要检查的每个单独的元属性。

例如,要收集帖子的纬度和经度(如果有),您需要编写:

SELECT p.ID, t1.slug_1, t2.slug_2, t3.slug_3, p1.latitude, p2.longitude
      FROM wp_posts    AS p
      LEFT JOIN
           (SELECT Post_ID, Meta_Key AS m1_key, Meta_Value AS latitude
              FROM wp_postmeta
             WHERE Meta_Key = 'latitude'
           ) AS p1 ON p.ID = p1.Post_ID
      LEFT JOIN
           (SELECT Post_ID, Meta_Key AS m2_key, Meta_Value AS longitude
              FROM wp_postmeta
             WHERE Meta_Key = 'longitude'
           ) AS p2 ON p.ID = p2.Post_ID
      JOIN (SELECT tr.Object_ID, tm.slug AS slug_1
              FROM wp_term_relationships AS tr
              JOIN wp_term_taxonomy      AS tt ON tr.term_taxonomy_id = tt.term_taxonomy_id
              JOIN wp_terms              AS tm ON tm.term_id = tt.term_id
             WHERE tm.slug IN ('academia', 'law', 'policy')
           ) AS t1 ON p.ID = t1.Object_ID
      JOIN (SELECT tr.Object_ID, tm.slug AS slug_2
              FROM wp_term_relationships AS tr
              JOIN wp_term_taxonomy      AS tt ON tr.term_taxonomy_id = tt.term_taxonomy_id
              JOIN wp_terms              AS tm ON tm.term_id = tt.term_id
             WHERE tm.slug IN ('full-time', 'part-time')
           ) AS t2 ON p.ID = t2.Object_ID
      JOIN (SELECT tr.Object_ID, tm.slug AS slug_3
              FROM wp_term_relationships AS tr
              JOIN wp_term_taxonomy      AS tt ON tr.term_taxonomy_id = tt.term_taxonomy_id
              JOIN wp_terms              AS tm ON tm.term_id = tt.term_id
             WHERE tm.slug = 'early-career'
           ) AS t3 ON p.ID = t3.Object_ID;

产生:

1575  policy  full-time  early-career  -33.8210366  151.1887557

等等。

于 2012-05-02T04:19:44.763 回答
0

将您的 IN 更改为 EXISTS;试试看——你会得到你的结果。

WHERE 
    wp_term_taxonomy.term_id exists (SELECT term_id FROM wp_terms 
        WHERE slug='academia' OR slug='law' OR slug='policy') AND
    wp_term_taxonomy.term_id exists(SELECT term_id FROM wp_terms 
        WHERE slug='full-time' OR slug='part-time') AND
    wp_term_taxonomy.term_id exists (SELECT term_id FROM wp_terms 
        WHERE slug='early-career') AND... //Rest of query/irrelevant
于 2012-05-02T04:19:24.440 回答
0

使用或:

wp_term_taxonomy.term_id IN (SELECT term_id FROM wp_terms 
    WHERE slug='academia' OR slug='law' OR slug='policy') 

OR wp_term_taxonomy.term_id IN (SELECT term_id FROM wp_terms 
    WHERE slug='full-time' OR slug='part-time') 

OR wp_term_taxonomy.term_id IN (SELECT term_id FROM wp_terms 
    WHERE slug='early-career') AND... //Rest of query/irrelevan

分析您的查询,不应该仅仅是:

wp_term_taxonomy.term_id IN (SELECT term_id FROM wp_terms 
    WHERE slug='academia' OR slug='law' OR slug='policy'
       OR slug='full-time' OR slug='part-time'
       OR slug='early-career') 
于 2012-05-02T04:26:20.907 回答