【问题标题】:SQL IN AND IN not workingSQL IN AND IN 不工作
【发布时间】:2012-05-02 04:04:05
【问题描述】:

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

我使用的是 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 过滤器,这不是我想要的。

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

谢谢!

【问题讨论】:

  • $-> 表示什么?它们不是普通的 SQL。您是否将 Perl 或其他东西嵌入到混合物中?
  • 对不起,我忘了说我使用的是 PHP(我使用的是 WordPress)。我的问题已更新,提到我正在使用它。对不起!

标签: php sql wordpress


【解决方案1】:

只看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),它必须与 Academia、Law 或 Policy 之一的术语 ID 同时相同(可能是 3 个不同的值),并且还与 Full 之一的术语 ID 相同-Time 或 Part-Time(可能是 2 个不同的值,并且与之前的 3 个值中的每一个都不同)并且也与 Early-Career 的术语 ID 相同(一个值,但与之前的 5 个值中的每一个都不同。所以,单项 ID 必须同时为 3 个不同的值,并且无法管理。

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

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 个别名是 wtt1wtt2wtt3。它们将列在 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_ID;在每种情况下都应该是tr.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。您将更改子查询以返回 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 (Entity-Attribute-Value) 模型。这将需要仔细处理以提取给定帖子的有用信息(例如纬度和经度)。实际上,您需要为每个要检查的单独元属性建立一个(可能是外部的)连接。

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

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

等等。

【讨论】:

  • 我知道你在做什么。那应该行得通。我目前正在尝试实施其他答案。我会用我找到的东西发回。谢谢!
  • 我更改了代码以反映您的答案,但即使使用别名,它仍然只能在选择一个“类别”时使用。
  • 哇,感谢您的广泛更新!我会努力实现这个!谢谢!
  • sigh 我希望我能这么先进。我会尽力让它发挥作用,但我认为这对我来说有点先进。感谢您的帮助,如果我知道如何实现它,我相信它会起作用。
  • 我不确定是否有办法使用以前的结果进行子查询(不是 IN 或 EXISTS)?难道我不能只通过查询运行我的结果 3 次(我知道它的效率非常低),每次都检查三个类别之一吗?
【解决方案2】:

将您的 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

【讨论】:

  • 欢迎来到 StackOverflow。请不要在 SO 上使用 SMS 缩写。请务必使用“代码”按钮(编辑框上方的{})将所选文本缩进为代码。这次我已经为你修好了,因为你是新来的。请不要再这样做了。
  • 我正在尝试这个,我会报告的。感谢您的回答!
  • 我修改了我的代码,现在它什么也没有返回。如果我保留它IN,我至少可以使用一个“类别”让它工作。改成EXISTS后,无论如何都找不到结果。
【解决方案3】:

使用 OR:

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

【讨论】:

  • 不完全。这就是现在的过滤器。它目前是一个全局 OR 过滤器。但是,我想确保返回的帖子在我的每个过滤器“类别”中至少包含一个词。
  • 假设 wp_term_taxonomy.term_id 为 1。学术、法律、政策、全职、兼职的 wp_terms.term_id 分别为 1、2、3、4、5。第一个条件将导致True,第二个条件(AND)永远不会为真,4,5 上没有一个匹配 taxonomy.term_id 的值。我认为 AND 在这里不是正确的条件
  • 这对我来说很有意义。我现在正在研究 Jonathan Leffler 的答案,因为他正确地解决了这个问题。我现在看到我正在做的是试图跨多个陈述分析一个术语,这永远不会是真的。
  • 好了,不用我多想了。 Jonathan Leffler 也有同样的想法stackoverflow.com/a/10407658/11432 你已经理解了这个问题stackoverflow.com/questions/10407549/sql-in-and-in-not-working/…
  • 没错,它永远不会是真的 :-) 一列不能有多个值
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-10-29
  • 2011-04-01
  • 2012-03-21
  • 2018-02-18
  • 2017-08-14
  • 1970-01-01
  • 2012-11-14
相关资源
最近更新 更多