Laravel 5.5:如何在同一Eloquent查询中组合whereIn与whereNotIn?
没问题,这需求用单条SQL就能搞定,还能保证效率,给你两种实用方案,顺便说下优化点:
首先先明确下你给出的表结构(方便大家理解):
-- buildings表(存储所有合法建筑ID) CREATE TABLE buildings ( id VARCHAR(10) PRIMARY KEY, building_name VARCHAR(50) ); -- 示例数据 INSERT INTO buildings VALUES ('a1', 'adam'), ('b2', 'barney'), ('c3', 'castor'); -- buildings_built表(存储已建成的建筑ID) CREATE TABLE buildings_built ( id INT PRIMARY KEY AUTO_INCREMENT, building_id VARCHAR(10) ); -- 示例数据 INSERT INTO buildings_built VALUES (1, 'a1');
方案1:LEFT JOIN + IS NULL(推荐,大表场景性能更稳定)
这是最常用的高效查询方式,利用左连接保留主表数据,再过滤掉已匹配的记录:
SELECT b.id FROM buildings b LEFT JOIN buildings_built bb ON b.id = bb.building_id WHERE b.id IN ('a1', 'b2', 'c3') AND bb.building_id IS NULL;
逻辑说明:
- 先把
buildings表和buildings_built表通过建筑ID关联 LEFT JOIN会保留buildings中所有符合IN条件的记录(不管有没有在buildings_built里)- 最后筛选出那些在
buildings_built中没有匹配项的记录(也就是bb.building_id IS NULL),这些就是你需要新建的建筑ID
方案2:NOT EXISTS子查询(可读性强)
如果你觉得子查询更直观,也可以用这个写法,现代数据库的优化器通常会把它优化成和JOIN差不多的执行计划:
SELECT b.id FROM buildings b WHERE b.id IN ('a1', 'b2', 'c3') AND NOT EXISTS ( SELECT 1 FROM buildings_built bb WHERE bb.building_id = b.id );
逻辑说明:
- 先筛选出
buildings中在目标数组里的记录 - 再排除掉那些在
buildings_built表中存在的记录
优化建议
为了让查询更快,记得给buildings_built的building_id字段加索引:
CREATE INDEX idx_buildings_built_building_id ON buildings_built(building_id);
(buildings的id已经是主键了,自带索引,不用额外加)
这样不管你的数据量多大,查询效率都会有保障,而且完全满足你的需求:既在目标数组、又在buildings表、且不在buildings_built表的有效建筑ID。
内容的提问来源于stack exchange,提问作者Wonka
相关产品推荐
相关产品推荐

