我有这两张桌子:
第一个是porttag
,第二个是portfolio
。基本上,porttag
是"投资组合标签"我将投资组合项目的标签关联起来。
我想通过portfolio
数据从porttag
过滤所有投资组合表。
我已经在使用此查询:
SELECT * FROM portfolio INNER JOIN porttag ON portfolio.id = porttag.port
但是这会返回重复的值,例如:
此可见性标记返回1项,包装标记返回2项。
我不想获得重复的商品。你能救我吗?
答案 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
,在此示例中,表示外部查询不会返回该行。