MySQL Left join 无法在单个查询中删除重复项

Posted

技术标签:

【中文标题】MySQL Left join 无法在单个查询中删除重复项【英文标题】:MySQL Left join cannot remove duplicates in a single query 【发布时间】:2020-05-10 20:48:13 【问题描述】:

我有 2 张桌子:

产品:

- id
- name

产品图片:

- id
- image
- product_id

我正在执行以下查询:

SELECT p.*, i.image
FROM products p
LEFT JOIN product_images i
ON p.id = i.product_id`
ORDER BY created_at DESC

但是,如果产品有几张图片,则此产品行是重复的。如何删除这些重复项,仅显示一对 p.id = i.product_id 中的第一个匹配项

【问题讨论】:

GROUP BY 应该可以帮到你。 请在代码问题中给出minimal reproducible example--cut & paste & runnable code,包括最小的代表性示例输入作为代码;期望和实际输出(包括逐字错误消息);标签和版本;明确的规范和解释。给出尽可能少的代码,即您显示的代码可以通过您显示的代码扩展为不正常的代码。 (调试基础。)对于包含 DBMS 和 DDL(包括约束和索引)和输入为格式化为表的代码的 SQL。 How to Ask 暂停总体目标的工作,将代码砍到第一个表达式,没有给出你期望的内容,说出你期望的内容和原因。 【参考方案1】:

对于这个数据集,简单的聚合应该可以做到:

SELECT p.*, min(i.image)
FROM products p
LEFT JOIN product_images i ON p.id = i.product_id
GROUP BY <enumerate all columns from products here>
ORDER BY created_at DESC
LIMIT $limit

如果您想要来自product_images 的更多列,那么您也可以使用相关子查询进行过滤;假设product_images 有主键id,看起来像:

SELECT p.*, i.image
FROM products p
LEFT JOIN product_images i 
    ON i.id = (SELECT MIN(i1.id) FROM product_images i1 WHERE i1.product_id = p.id)
ORDER BY created_at DESC
LIMIT $limit

【讨论】:

谢谢,在您的第一个示例中,您写道:GROUP BY &lt;enumerate all columns from products&gt;,如果我有 40 列怎么办?我可以发GROUP BY p.*吗? @AlexanderKim:我不认为这是有效的语法。而且,一般来说,枚举列而不是使用* 是一种很好的做法(例如,这样可以避免在向表中添加新列时破坏查询结果)。 @AlexanderKim:这真的取决于你的数据集......你需要测试这两个选项,看看哪个表现更好。【参考方案2】:

如果image的数据类型是varchar或int,那么不要加入表product_images,而是加入每个产品图像的MIN:

SELECT p.*, i.image
FROM products p
LEFT JOIN (
  SELECT product_id, MIN(image) image
  FROM product_images 
  GROUP BY product_id
) i
ON p.id = i.product_id
ORDER BY created_at DESC
LIMIT $limit

【讨论】:

以上是关于MySQL Left join 无法在单个查询中删除重复项的主要内容,如果未能解决你的问题,请参考以下文章

Linq2Sql:即使返回单个记录,也始终执行 LEFT JOIN

单个 Prisma 查询中的 LEFT JOINS 和聚合

MySql 之 left join 查询结果

Mysql 连接(left join, right join, inner join ,full join)

MySQL 的子查询和left join的比较,啥时候用子查询效率高,啥时候用left join效率高?

mysql多表left join联合查询效率问题5