使用内部联接并限制数据重复

时间:2016-10-11 16:03:20

标签: php mysql join inner-join

我有这两张桌子:

enter image description here

enter image description here

第一个是porttag,第二个是portfolio。基本上,porttag是"投资组合标签"我将投资组合项目的标签关联起来。

我想通过portfolio数据从porttag过滤所有投资组合表。

我已经在使用此查询:

SELECT * FROM portfolio INNER JOIN porttag ON portfolio.id = porttag.port

但是这会返回重复的值,例如:

此可见性标记返回1项,包装标记返回2项。

我不想获得重复的商品。你能救我吗?

1 个答案:

答案 0 :(得分:0)

有两种方法可以避免产生重复。一种是使用返回唯一值的内联视图,并加入到该视图中。另一种方法是使用EXISTS (correlated subquery)模式。

另一种方法是继续生成重复项,但随后使用GROUP BY子句将其折叠。 (我不推荐这种方法。我之所以提到它只是因为它是一个选项。)对于现有的查询,您可以添加GROUP BY portfolio.id。但是,将填充porttag列的哪一行是不确定的。 (默认情况下,MySQL中的非标准扩展将允许查询运行。其他数据库会抛出错误。我们可以使MySQL更加符合标准,并通过在sql_mode中包含ONLY_FULL_GROUP_BY来抛出错误。)I不推荐这种方法。

内联视图示例

由于v子句,内联视图port会返回GROUP BY的唯一值。当有多个标记时,我们使用聚合(在这种情况下为MIN())来选择要返回的标记值。

 SELECT p.*
      , v.port
      , v.tag
   FROM ( SELECT t.port
               , MIN(t.tag) AS tag 
            FROM porttag t
           GROUP BY t.port
         ) v
    JOIN portfolio p
      ON p.id = v.port

此模式符合关于使用内部联接操作的规范。

EXISTS(相关子查询)示例

如果"内部联接"不是要求,如果我们不需要从porttag返回任何列,我们可以避免加入操作...

SELECT p.*
  FROM portfolio p
 WHERE EXISTS ( SELECT 1 
                  FROM porttag t 
                 WHERE t.port = p.id   -- related to outer row
              )

对于外部查询返回的每一行,将评估EXISTS后面的子查询。如果子查询返回一行或多行,EXISTS将计算为TRUE,并返回外部查询中的行。如果子查询没有返回任何行,则EXISTS计算为FALSE,在此示例中,表示外部查询不会返回该行。