如何在Kotlin Exposed中对多列使用NOT IN列表查询?
不用原生SQL实现复合条件DELETE的方案
针对你需要的删除逻辑——删除foreignKeyIdColumn等于指定值,且(column1, column2)不在给定复合值列表中的记录,以下是几种替代原生SQL的实现方式,适配不同技术栈和场景:
1. 子查询关联筛选(适合SQL查询构建器)
如果用MyBatis这类支持SQL拼接的框架,可以用左关联子查询的方式改写,避免直接写复合NOT IN语法:
DELETE t FROM your_table t LEFT JOIN ( SELECT 'value1' AS col1, 'value2' AS col2 UNION ALL SELECT 'value3' AS col1, 'value4' AS col2 ) keep_rows ON t.column1 = keep_rows.col1 AND t.column2 = keep_rows.col2 WHERE t.foreignKeyIdColumn = 'foreignKeyIdValue' AND keep_rows.col1 IS NULL;
这种写法可以通过框架的动态SQL功能,动态拼接UNION ALL的部分,灵活添加要保留的复合值对。
2. ORM框架的API构建(以JPA/Hibernate为例)
如果用JPA或Hibernate,完全可以通过Criteria API构建复合条件,无需原生SQL:
CriteriaBuilder cb = entityManager.getCriteriaBuilder(); CriteriaDelete<YourEntity> deleteQuery = cb.createCriteriaDelete(YourEntity.class); Root<YourEntity> root = deleteQuery.from(YourEntity.class); // 定义要保留的复合值集合 List<Object[]> retainedPairs = Arrays.asList( new Object[]{"value1", "value2"}, new Object[]{"value3", "value4"} ); // 构建"保留条件"的或逻辑 Predicate retainCondition = cb.disjunction(); for (Object[] pair : retainedPairs) { retainCondition = cb.or(retainCondition, cb.and( cb.equal(root.get("column1"), pair[0]), cb.equal(root.get("column2"), pair[1]) ) ); } // 组装最终删除条件 deleteQuery.where( cb.equal(root.get("foreignKeyIdColumn"), "foreignKeyIdValue"), cb.not(retainCondition) ); entityManager.createQuery(deleteQuery).executeUpdate();
如果你的实体类映射了复合主键(比如用@EmbeddedId或@IdClass),后续也可以扩展为查询出待删除的主键集合再批量删除,更灵活。
3. 查询+批量删除(适合小数据量场景)
如果表数据量不大,可以分两步操作:
- 第一步:查询出所有符合删除条件的复合主键:
SELECT pk_col1, pk_col2 FROM your_table WHERE foreignKeyIdColumn = 'foreignKeyIdValue' AND (column1, column2) NOT IN (('value1', 'value2'), ('value3', 'value4'));
- 第二步:通过ORM的批量删除接口,传入这些复合主键集合完成删除(比如MyBatis的批量delete方法,接收主键列表参数)。
关键注意点
- 复合主键映射:确保你的实体类正确映射了表的复合主键,这是ORM框架处理批量操作的前提。
- 索引优化:给
foreignKeyIdColumn、column1、column2建立联合索引,能大幅提升查询和删除的性能,尤其是数据量大的表。
内容的提问来源于stack exchange,提问作者cjs
相关产品推荐
相关产品推荐

