当IN(...)子句包含重复值时,如何返回对应重复结果?
解决IN子句无法返回重复匹配项的问题
这事儿我熟!IN子句本身会自动去重,哪怕你写WHERE id IN (1,1,2),数据库也会优化成WHERE id IN (1,2),所以自然不会返回重复结果。要让结果跟着你的输入列表保留重复项,得换个思路——把你的重复值列表转换成一个带重复行的临时数据集,再和原表做JOIN关联就行。
下面给你列几个不同数据库的实现方式,挑你用的来:
通用方案(所有数据库都适用)
用CTE(公共表表达式)构造包含重复值的临时表,再JOIN原表:
WITH target_values AS ( SELECT 1 AS val UNION ALL -- 必须用UNION ALL,UNION会去重! SELECT 1 AS val UNION ALL SELECT 2 AS val ) SELECT t.* FROM your_table t JOIN target_values tv ON t.id = tv.val;
这里核心是UNION ALL,它会保留所有重复行,不像UNION会自动去重。
MySQL/MariaDB 简化写法
直接用VALUES语句快速构造临时数据集:
SELECT t.* FROM your_table t JOIN (VALUES (1), (1), (2)) AS tv(val) ON t.id = tv.val;
PostgreSQL 两种写法
除了上面的VALUES方式,还可以用数组展开函数unnest,适合动态传入数组的场景:
-- 方式1:VALUES SELECT t.* FROM your_table t JOIN (VALUES (1), (1), (2)) AS tv(val) ON t.id = tv.val; -- 方式2:数组展开 SELECT t.* FROM your_table t JOIN unnest(ARRAY[1,1,2]) AS tv(val) ON t.id = tv.val;
SQL Server 写法
同样支持VALUES,如果你的重复值是来自字符串(比如'1,1,2'),可以用STRING_SPLIT:
-- 方式1:VALUES SELECT t.* FROM your_table t JOIN (VALUES (1), (1), (2)) AS tv(val) ON t.id = tv.val; -- 方式2:处理字符串输入 SELECT t.* FROM your_table t JOIN STRING_SPLIT('1,1,2', ',') AS tv ON t.id = CAST(tv.value AS INT);
原理说明
IN子句是集合匹配,只关心值是否存在;而JOIN是行匹配,临时数据集里有多少行,就会做多少次匹配。所以只要临时数据集保留了你的重复值,JOIN后就能得到对应次数的结果行。
内容的提问来源于stack exchange,提问作者AnCo ngCo Danh Bun
相关产品推荐
相关产品推荐

