【问题标题】:How to avoid Cartesian product in an INNER JOIN query?如何在 INNER JOIN 查询中避免笛卡尔积?
【发布时间】:2010-05-20 09:00:55
【问题描述】:

我有 6 张桌子,我们称它们为 a、b、c、d、e、f。现在我想在所有表的所有列(ID 列除外)中搜索某个单词,比如说“Joe”。我所做的是,我对所有表进行了 INNER JOINS,然后使用 LIKE 搜索列。

INNER JOIN
...
ON
INNER JOIN
...
ON.......etc.
WHERE a.firstname 
~* 'Joe' 
OR a.lastname 
~* 'Joe' 
OR b.favorite_food 
~* 'Joe'
OR c.job
~* 'Joe'.......etc.

结果是正确的,我得到了我正在寻找的所有列。但我也得到了某种笛卡尔积,我得到了 2 条或更多行的结果几乎相同。

我怎样才能避免这种情况?我希望每行只有一次,因为结果应该出现在网络搜索中。

更新

我首先尝试通过使用以下语句来确定SELECT DISTINCT 是否可以工作:pastie.org/970959 但它仍然给了我一个笛卡尔积。这有什么问题?

【问题讨论】:

  • 请说明你使用什么数据库。

标签: sql inner-join cartesian-product


【解决方案1】:

试试SELECT DISTINCT

【讨论】:

  • ms sql server 还是有select distinct,不是吗?
  • 好像有区别。
【解决方案2】:

你在什么条件下JOIN这个tables?你有foreign keys 什么的吗?

也许你应该在每张桌子上分别找到那个词?

【讨论】:

  • 我在表之间有关系,所以我对 person_has_job 表进行 INNER JOIN 并从那里到 job 表。
【解决方案3】:

您使用的是哪种服务器? Microsoft SQL Server 具有全文索引功能(我认为其他人也有类似的功能),可让您以更少资源密集型的方式搜索关键字。

还可以考虑使用 UNION 而不是加入表。

【讨论】:

    【解决方案4】:

    没有看到你的表,我只能假设这里发生的事情是你在某个地方有一个一对多的关系。您可能希望在子查询中执行所有操作,选择不同的 ID,然后按 ID 获取要显示的数据。比如:

    SELECT a.*, b.*
    FROM (SELECT DISTINCT a.ID
          FROM ...
          INNER JOIN ...
          INNER JOIN ...
          WHERE ...) x
    INNER JOIN a ON x.ID = a.ID
    INNER JOIN b ON x.ID = b.ID
    

    不过有几点需要注意:

    • 这将是 sloooow,您可能希望使用全文搜索(如果您的 RDBMS 支持的话)。

    • 单独搜索每个表可能比先连接笛卡尔积中的所有内容然后使用 OR 过滤更快。

    【讨论】:

    • 这可能是解决方案,我会尝试的。谢谢!
    • 好,那我看看postgresql全文搜索。
    • 我首先尝试通过使用以下语句来确定 SELECT DISTINCT 是否可行:pastie.org/970959 但它仍然给了我一个笛卡尔积。这有什么问题?
    • @flhe 然后看看你的 JOIN - 你可能在某处有多个匹配的记录。例如,可能是类别表或其他东西?
    【解决方案5】:

    如果您的表格是实体类型表格,例如 a 是个人,b 是公司,我认为如果您在这种方式(单个查询)。

    您说您想在所有表中搜索某个单词,但您可能希望将结果分成相应的类型。对?否则,网络搜索将没有多大意义。 因此,如果您搜索“Joe”,您希望看到包含名称“Joe”的人,例如名为“Joe's gym”的公司。由于您正在搜索不同的实体,因此您应该将搜索拆分为不同的查询。

    如果您真的想在一个查询中执行此操作,则必须更改数据库结构以适应。您将需要某种形式的“搜索表”,其中包含实体 ID (PK) 和实体类型,以及您希望找到该实体的关键字列表。例如:

    EntityType, EntityID, Keywords
    ------------------------------
    Person,     4,        'Joe', 'Doe'
    Company,    12,       'Joe''s Gym', 'Gym'
    

    类似的东西?

    但是当您的搜索仅返回一种类型的实体(例如人员)并且您想要返回您在该关键字上获得命中的人员时(在与该关键字相关的任何表中),情况就不同了人)。然后,您需要选择所有要显示的字段并按它们分组,而忽略您正在搜索的字段。包括它们不可避免地会导致笛卡尔积。

    顺便说一句,我只是在这里进行头脑风暴。希望对您有所帮助。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-05-27
      • 2017-02-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-06
      • 1970-01-01
      • 2019-10-20
      相关资源
      最近更新 更多