【问题标题】:Apply filter on joined tables with MySQL使用 MySQL 对连接表应用过滤器
【发布时间】:2012-06-15 14:43:44
【问题描述】:

我在 MySQL 中存储了一些数据,并希望过滤掉符合给定条件的行。

听起来很简单,但实际上并不容易,因为涉及到一些连接条件。

我确实有以下表格:

items : id, ...
genres: id, name:varchar, item_id

每个项目都有多种类型。

如果至少一个流派确实与给定流派名称(或一组名称)匹配,则查询应过滤 out 项。

例如:

Item with id 1 has 3 genres
  - genre name = 'foo'
  - genre name = 'bar'
  - genre name = 'baz'

如果给定的流派名称是 'bar'、['bar'、'baz'、'xyz'] 等,则项目 1 可能不是结果集的一部分。

我尝试离开加入项目的流派并应用带有“genres.name NOT IN (?)”的 WHERE 语句。 ?是给定的流派名称集。

这(当然)只适用于只有一种类型的项目。同样可以通过多个 WHERE 条件来实现:WHERE name 'a' AND name 'b' ...

任何想法如何正确完成此查询?

提前致谢!

【问题讨论】:

  • 能否请您提供一个示例查询,说明它的作用,然后说明您希望它做些什么不同的事情?
  • 我还不明白这些表...所以你有一个items 表和一个genres 表。为什么后一个表有一个item_id 列?我希望看到一个多对多关联表,它将项目与流派联系起来。
  • 如果至少有一个流派与给定的流派名称匹配,为什么要过滤掉项目?在问题的第一行中,你写了相反的内容。
  • 就@RaviJain 而言,您的示例与上面您想要的结果描述不匹配。根据您的描述,第 1 项 将 成为结果集的一部分,因为它包含 bar,不是吗?

标签: mysql join filter


【解决方案1】:

你可以这样做 (see sqlfiddle):

select i.name as item, g.name as genre
from items as i
left join genres as g
  on i.id = g.item_id 
where i.id not in
      (select distinct g2.item_id from genres as g2
       where FIND_IN_SET(g2.name,'foo,bar'));

如果您想检查多个流派名称,这种方式可以工作。

【讨论】:

  • 谢谢!也看看bernies方法。也解决了问题。
【解决方案2】:

您可以使用相关子查询。
示例:

SELECT id 
FROM   items i
WHERE  NOT EXISTS (SELECT 1 
                   FROM   genres g
                   WHERE  g.`name` = 'bar' 
                   AND    i.id = g.item_id);

相关子查询与其他子查询的不同之处在于它引用了外部查询。
为外部查询投影/选择的每一行运行相关子查询。

【讨论】:

  • 我想这正是我想要的。谢谢伯尼!
【解决方案3】:

希望我能理解您的要求,并且我认为 MySQL 和 T-SQL 在这方面将是相似的。这些是我假设您在示例中使用的示例表。

Table1
ID  NAME
1   Item 1
2   Item 2
3   Item 3
4   Item 4
5   Item 5
6   Item 6

Table2
ID  NAME    ITEM_ID
1   Genre 1   1
2   Genre 2   1
3   Genre 3   1
4   Genre 1   2
5   Genre 2   2
6   Genre 3   2
7   Genre 1   3
8   Genre 2   3
9   Genre 3   3
10  Genre 1   4

如果项目符合您的条件之一,这里是用于过滤 out 项的 SQL。

SELECT *
FROM table1 a, table2 b
WHERE a.id = b.item_id
AND b.name NOT IN ('Genre 1', 'Genre 2')

上述查询对样本表返回的结果。

ID  NAME    ID_1    NAME_1  ITEM_ID
1   Item 1    3 Genre 3   1
2   Item 2    6 Genre 3   2
3   Item 3    9 Genre 3   3

您也可以改为过滤掉genre_id (table2.id)。如果您打算使用子查询而不是硬编码值,那么您应该将“NOT IN”切换为“NOT EXISTS”并相应地重写“AND”部分,因为“NOT IN”不喜欢空值。

此查询还假定每个“项目”至少有 1 个“流派”。如果您想要所有“项目”(不包括符合您条件的项目),我相信您可以使用它。

【讨论】:

  • 谢谢,但这不起作用,因为必须提供一个项目的所有流派名称才能将该项目从列表中删除。至少一个匹配的流派名称应该可以完成这项工作。
【解决方案4】:
select * from items i where not exists 
(select '' from genres gen where gen.item_id = i.id and gen.name in ('foo','pop') )

更短更简单的查询。 内部查询检查关键字列表中的流派名称,如果没有返回行,则选择外部查询的当前行。
验证输出 at here.

感谢Kyra ,我从 sql fiddle 借用了他的架构。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-01-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-06-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多