SQL语句_多表联查——插入或者更新

小咸儿根据业务需求做定时同步数据任务,需将A表数据定时同步到B表,先进行多表联查,再添加记录。当记录存在时执行更新操作,用到关键句on duplicate key update。使用该语句要注意有唯一字段,且不能加where条件。

  最近小咸儿根据业务需求,做一个定时同步数据的任务。

业务需求:

  A表要定时将数据同步到B表中,但是这其中还涉及到了其他的表,所以第一步需要进行多表联查。

SELECT
	user_id,
	user_name,
	user_code,
	organization_name
FROM
	`tc_organization_user` AS tc LEFT JOIN tik_user AS tk ON tc.user_id = tk.id LEFT JOIN tc_organization AS tco ON tco.id = tc.organization_id
WHERE
	organization_id = '*************' 

  将数据查询出来之后,第二步则需要添加记录,这时候需要注意的是,当记录存在时,则执行更新操作。这里就需要用到关键句 on duplicate key update

作用: 这个语句的作用就是,当执行SQL语句时,如果存在该记录则执行更新操作,如果不存在该记录则执行插入操作。

INSERT INTO tim_mentorship_user ( id, user_name, user_code, user_grade, create_time, update_time, operator, creator, remark, is_delete ) SELECT DISTINCT
	user_id,
	user_name,
	user_code,
	organization_name,
	tk.create_time,
	tk.update_time,
	tk.operator,
	tk.creator,
	tk.remark,
	tk.is_delete 
FROM
	tc_organization_user AS tc
	LEFT JOIN tik_user AS tk ON tc.user_id = tk.id
	LEFT JOIN tc_organization AS tco ON tco.id = tc.organization_id 
WHERE
	tk.is_delete = 0 AND
	organization_id = '**************'
	ON DUPLICATE KEY UPDATE user_name = tk.user_name,
	user_code = tk.user_code,
	user_grade = tco.organization_name,
	create_time = tk.create_time,
	update_time = now(),
	operator = tk.operator,
	creator = tk.creator,
	remark = tk.remark,
	is_delete = tk.is_delete

注意点: 使用该语句,需要注意两点:

  • 判断该条记录是否存在的标准是什么?也就是说必须有一个字段是唯一不能重复的
  • on duplicate key update 语句是不能添加where条件的

感谢您的阅读~

在 MyBatis-Plus 中,**`LambdaQueryWrapper` 本身不支持直接多表联查(如 LEFT JOIN、INNER JOIN)**,因为它是基于单的条件构造器。但你可以通过以下 **几种方式结合 `LambdaQueryWrapper` 实现查询逻辑**。 --- ## ✅ 方案一:使用 `@Select` + 自定义 SQL(推荐) 这是最常见、最灵活的方式 —— 在 Mapper 中写原生 SQL 进行多表联查,并用 `LambdaQueryWrapper` 构造动态条件传入。 ### 示例场景: 查询用户及其所属部门名称(User 和 Dept 关联) ```sql SELECT u.*, d.dept_name FROM user u LEFT JOIN dept d ON u.dept_id = d.id WHERE ... ``` ### 步骤 1:实体类扩展字段 ```java @Data @EqualsAndHashCode(callSuper = false) @Accessors(chain = true) public class UserVO extends User { private String deptName; // 扩展字段 } ``` ### 步骤 2:Mapper 接口定义自定义 SQL ```java public interface UserMapper extends BaseMapper<User> { /** * 多表联查 + 动态条件 */ @Select("SELECT u.*, d.dept_name AS dept_name " + "FROM user u " + "LEFT JOIN dept d ON u.dept_id = d.id " + "WHERE 1=1 " + "<if test='name != null and name !=\"\"'> AND u.name LIKE CONCAT('%', #{name}, '%') </if>" + "<if test='deptId != null'> AND u.dept_id = #{deptId} </if>" + "<if test='minAge != null'> AND u.age >= #{minAge} </if>" + "ORDER BY u.create_time DESC") List<UserVO> selectUserWithDept(@Param("name") String name, @Param("deptId") Long deptId, @Param("minAge") Integer minAge); } ``` ### 步骤 3:Service 层调用(可结合 Lambda 构造条件) 虽然这里没直接用 `LambdaQueryWrapper` 写 JOIN,但可以用它来提取参数或验证逻辑: ```java @Service public class UserService { @Autowired private UserMapper userMapper; public List<UserVO> getUsersWithDept(String name, Long deptId, Integer minAge) { // 可以先用 LambdaQueryWrapper 做一些前置校验或日志记录 LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>(); wrapper.like(StringUtils.hasText(name), User::getName, name) .eq(deptId != null, User::getDeptId, deptId) .ge(minAge != null, User::getAge, minAge); // 输出最终 SQL(仅用于调试) System.out.println("Generated Condition SQL: " + wrapper.getCustomSqlSegment()); // 调用自定义 SQL 查询 return userMapper.selectUserWithDept(name, deptId, minAge); } } ``` > 🔔 注意:`wrapper.getCustomSqlSegment()` 只能获取 WHERE 条件部分,不能替代完整 JOIN 查询。 --- ## ✅ 方案二:使用 `QueryWrapper` 的 `apply` 方法拼接 SQL(轻量级) 如果你不想写 XML 或注解 SQL,可以用 `apply` 插入自定义 JOIN 语句。 ```java LambdaQueryWrapper<UserVO> wrapper = new LambdaQueryWrapper<>(); wrapper.select(UserVO::getId, UserVO::getName, UserVO::getAge, UserVO::getDeptName) .apply("u.dept_id = d.id") .like(StringUtils.hasText(name), UserVO::getName, name) .orderByDesc(UserVO::getCreateTime); // ❌ 但是!这无法实现真正的 JOIN,除非你把别名也处理好 ``` ⚠️ **局限性大**:这种方式只能拼接 WHERE 后的条件,不能控制 FROM 和 JOIN 子句。 所以更推荐下面这种 **XML 配合 QueryWrapper** 的方式。 --- ## ✅ 方案三:使用 XML 配置 + `@Param("ew")` 接收 Wrapper(高级用法) ### 步骤 1:Mapper 接口方法 ```java List<UserVO> selectUserJoinWithWrapper(@Param("ew") LambdaQueryWrapper<UserVO> wrapper); ``` ### 步骤 2:XML 文件中编写 JOIN 查询并引用 Wrapper ```xml <!-- UserMapper.xml --> <select id="selectUserJoinWithWrapper" resultType="com.example.UserVO"> SELECT u.*, d.dept_name AS deptName FROM user u LEFT JOIN dept d ON u.dept_id = d.id <where> ${ew.customSqlSegment} <!-- 注入 LambdaQueryWrapper 的条件 --> </where> </select> ``` ### 步骤 3:Service 调用 ```java LambdaQueryWrapper<UserVO> wrapper = new LambdaQueryWrapper<>(); wrapper.like(UserVO::getName, "张") .ge(UserVO::getAge, 18); List<UserVO> users = userMapper.selectUserJoinWithWrapper(wrapper); ``` ✅ 优点: - 条件动态生成由 MP 完成 - JOIN 查询由 SQL 控制 - 安全且高效 --- ## ✅ 方案四:使用 `BaseMapper` 的子查询功能(有限支持) MyBatis-Plus 支持一些“伪”操作,比如子查询: ```java LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>(); wrapper.in(User::getDeptId, new QueryWrapper<Dept>().select("id").eq("status", 1).getCustomSqlSegment() ); ``` 但这仍然不是真正意义上的 JOIN,适合简单场景。 --- ## ✅ 总结对比 | 方案 | 是否推荐 | 适用场景 | 说明 | |------|----------|-----------|-------| | ✅ 自定义 SQL (`@Select`) | ⭐⭐⭐⭐☆ | 通用、高性能 | 最常用,配合 VO 使用 | | ✅ XML + `${ew.customSqlSegment}` | ⭐⭐⭐⭐ | 复杂动态条件 | 灵活,推荐用于复杂业务 | | ✅ `apply()` 拼接 SQL | ⭐⭐ | 简单条件 | 易出错,不推荐主流程使用 | | ❌ 单纯使用 `LambdaQueryWrapper` | ❌ | 不支持 | 无法实现 JOIN | --- ###
评论 17
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值