MySQL分组查询每组最新的一条数据(通俗易懂)

开发中经常会遇到,分组查询最新数据的问题,比如下面这张表(查询每个地址最新的一条记录):

 平常我们会进行按照时间倒叙排列然后进行分组,获取每个供应商的最新记录,sql如下:

SELECT * FROM(
SELECT
            tms.id supplierId,
            tms.name supplierName,
            tms.contact_name contactName,
            tms.contact_phone contactPhone,
            til.`material_id` materialId,
            til.recent_quotation recentQuotation,
            til.quote_time 
        FROM
            tenant_inquiry_library til
            LEFT JOIN tenant_material_supplier tms
                ON til.supplier_id = tms.id
        WHERE
            til.material_id = 1377127968075161602
        ORDER BY til.quote_time DESC
        ) a GROUP BY a.supplierId

但是查询结果却不是我们想要的:

很显然,并没有像我们想象中的按报价时间倒叙排序,这是为什么呢?

因为在mysql5.7的时候,子查询的排序已经变为无效了,可能是因为子查询大多数是作为一个结果给主查询使用,所以子查询不需要排序的原因。

那么我们应该怎么查呢,有一下方式:


SELECT * FROM(
SELECT
            tms.id supplierId,
            tms.name supplierName,
            tms.contact_name contactName,
            tms.contact_phone contactPhone,
            til.`material_id` materialId,
            til.recent_quotation recentQuotation,
            til.quote_time 
        FROM
            tenant_inquiry_library til
            LEFT JOIN tenant_material_supplier tms
                ON til.supplier_id = tms.id
        WHERE
            til.material_id = 1377127968075161602
        ORDER BY til.quote_time DESC LIMIT 10000
        ) a GROUP BY a.supplierId

结果为:

对子查询的排序进行limit限制,此时子查询就不光是排序,所以此时排序会生效,但是限制条数却只能尽可能的设置大些

<think>好的,我现在要详细解释MySQL的JOIN语法。首先,我需要回忆一下自己知道的关于JOIN的内容,可能包括不同类型的JOIN,比如INNER JOIN、LEFT JOIN、RIGHT JOIN,还有FULL JOIN?不过可能MySQL不支持FULL JOIN?这点需要确认。 用户的问题是要求介绍MySQL的JOIN语法,所以需要涵盖基本语法结构,各种JOIN的区别,以及使用场景。可能需要举例说明,这样更清晰。同时要注意语法的正确性,比如ON和USING子句的区别,还有自然连接NATURAL JOIN,虽然可能不常用,但应该提一下。 首先,JOIN的作用是合并两个或多个表的行,基于相关的列。这是关系型数据库的核心功能之一。不同的JOIN类型决定了如何合并数据。比如INNER JOIN只返回匹配的行,而LEFT JOIN会返回左表的所有行,即使右表没有匹配。 接下来,需要详细说明每种JOIN的语法和示例。比如INNER JOIN的基本写法,然后是LEFT JOIN,RIGHT JOIN,还有CROSS JOIN。注意CROSS JOIN会产生笛卡尔积,可能在实际中较少使用,但也需要提及。 同时,可能需要注意MySQL和其他数据库在JOIN实现上的差异,比如MySQL不支持FULL OUTER JOIN,但可以通过UNION LEFT JOIN和RIGHT JOIN来模拟。这个点对用户可能有帮助,应该包括进去。 另外,使用ON和WHERE的区别。ON是连接条件,而WHERE是在连接后过滤结果。特别是在LEFT JOIN时,如果将条件放在ON和WHERE中的不同效果,比如ON后面的条件会影响连接过程,而WHERE则是在连接后过滤,可能导致不同的结果。 还需要提到USING子句,当连接的两个表的列名相同时,可以使用USING来简化语法,比如JOIN ... USING (column_name)。这可能比ON更简洁。 自然连接NATURAL JOIN可能自动根据相同列名连接,但容易出错,所以通常不推荐使用,但需要提及存在这个选项。 示例部分很重要,最好用具体的表结构和数据来演示不同JOIN的效果。例如,假设有两个表,用户表和订单表,通过用户ID连接,展示不同JOIN的结果差异。 总结一下结构: 1. JOIN的作用和基本概念 2. 各种JOIN类型:INNER, LEFT, RIGHT, CROSS,以及FULL JOIN的模拟方法 3. 语法结构,包括ON、USING、NATURAL JOIN 4. 使用示例和结果说明 5. 注意事项,比如性能考虑,连接条件的正确性等 在写作过程中要确保术语正确,比如“行”而不是“记录”,但可能需要用更通俗的语言。同时,注意中文表达,避免直译英文导致的生硬。 最后检查是否有遗漏,比如隐式连接(使用逗号分隔表,并在WHERE中指定条件)是否应该提及,虽然现在推荐使用显式JOIN语法。还有JOIN的性能优化,比如索引的重要性,但可能超出当前问题的范围,可以简单提到。 现在组织这些内容,确保逻辑清晰,分点说明,示例易懂。</think>MySQL中的JOIN操作用于将多个表中的数据关联查询,核心是通过匹配列值合并数据。以下是详细说明: --- ### 一、基本JOIN类型与语法 #### 1. INNER JOIN(内连接) - **作用**:仅返回两个表中匹配的行。 - **语法**: ```sql SELECT 列名 FROM 表1 INNER JOIN 表2 ON 表1.列 = 表2.列; ``` - **示例**: ```sql SELECT users.name, orders.amount FROM users INNER JOIN orders ON users.id = orders.user_id; ``` *结果仅包含有订单的用户。* #### 2. LEFT JOIN(左连接) - **作用**:返回左表所有行,右表无匹配时显示`NULL`。 - **语法**: ```sql SELECT 列名 FROM 表1 LEFT JOIN 表2 ON 表1.列 = 表2.列; ``` - **示例**: ```sql SELECT users.name, orders.amount FROM users LEFT JOIN orders ON users.id = orders.user_id; ``` *结果包含所有用户,无订单的显示`NULL`。* #### 3. RIGHT JOIN(右连接) - **作用**:返回右表所有行,左表无匹配时显示`NULL`。 - **语法**: ```sql SELECT 列名 FROM 表1 RIGHT JOIN 表2 ON 表1.列 = 表2.列; ``` - **注意**:可通过调换表顺序用LEFT JOIN替代,更常用LEFT JOIN。 #### 4. CROSS JOIN(交叉连接) - **作用**:生成笛卡尔积(所有行的组合)。 - **语法**: ```sql SELECT 列名 FROM 表1 CROSS JOIN 表2; ``` - **用途**:适用于需要组合所有可能的场景(如生成测试数据)。 --- ### 二、特殊语法与技巧 #### 1. 使用`USING`简化同名列 - 当连接列名相同时: ```sql SELECT 列名 FROM 表1 INNER JOIN 表2 USING (共同列名); ``` #### 2. 自然连接`NATURAL JOIN` - 自动匹配所有同名列(慎用,易出错): ```sql SELECT 列名 FROM 表1 NATURAL JOIN 表2; ``` #### 3. 模拟`FULL OUTER JOIN` - MySQL不支持`FULL JOIN`,但可通过`UNION`实现: ```sql SELECT * FROM 表1 LEFT JOIN 表2 ON ... UNION SELECT * FROM 表1 RIGHT JOIN 表2 ON ...; ``` --- ### 三、连接条件的关键点 1. **`ON` vs `WHERE`**: - `ON`定义连接条件(影响连接过程)。 - `WHERE`在连接后过滤结果。 - *示例*:LEFT JOIN中若将右表条件放在`WHERE`会导致过滤掉`NULL`行。 2. **多表连接**: ```sql SELECT ... FROM 表1 JOIN 表2 ON ... JOIN 表3 ON ...; ``` --- ### 四、性能与注意事项 1. **索引优化**:确保连接列上有索引。 2. **避免过多JOIN**:复杂JOIN可能降低性能。 3. **明确连接类型**:错误选择JOIN类型会导致数据不准确。 --- ### 五、示例表说明 假设有两个表: - **`users`表**: | id | name | |----|-------| | 1 | Alice | | 2 | Bob | - **`orders`表**: | user_id | amount | |---------|--------| | 1 | 100 | | 1 | 200 | **不同JOIN结果对比**: - **INNER JOIN**:仅Alice的2条订单。 - **LEFT JOIN**:Alice 2条,Bob显示`NULL`。 - **RIGHT JOIN**:同INNER JOIN(若orders无多余数据)。 - **CROSS JOIN**:2用户 × 2订单 = 4行组合。 --- 掌握JOIN语法能高效关联数据,但需谨慎选择类型并优化查询性能。
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

乃真卧龙凤雏

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值