【问题标题】:Use Inner Join and limit data repeat使用 Inner Join 并限制数据重复
【发布时间】:2016-10-11 16:03:19
【问题描述】:

我有这两张桌子:

第一个是porttag,第二个是portfolio。基本上,porttag 是“投资组合标签”,我在其中关联投资组合项目的标签。

我想从 portfolio 中获取所有 Portfolio 表,这些表由 porttag 数据过滤。

我已经在使用这个查询了:

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

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

这将返回可见性标签中的 1 件商品和包装标签中的 2 件商品。

我不想得到重复的项目。你能帮帮我吗?

【问题讨论】:

  • 显示您的预期结果..

标签: php mysql join inner-join


【解决方案1】:

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

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

内联视图示例

由于GROUP BY 子句,内联视图v 返回port 的唯一值。当有多个标签时,我们使用聚合(在本例中为 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,在此示例中,这意味着外部查询不会返回该行。

【讨论】:

  • 在第一个版本中,可能使用GROUP_CONCAT(t.tag),这样您就可以看到所有标签名称,而不仅仅是第一个。
猜你喜欢
  • 2016-03-25
  • 2013-07-13
  • 2012-04-26
  • 1970-01-01
  • 1970-01-01
  • 2012-07-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多