DuckDB子查询返回多列报错问题及替代查询方法咨询
DuckDB多列IN子查询报错问题及解决方案
问题背景
需求:按first_name分组,提取每个分组中age最小的用户完整记录。
- 某在线SQL编译器中可正常运行的查询语句:
SELECT * FROM customer WHERE (first_name, age) IN ( SELECT first_name, min(age) FROM customer GROUP BY first_name )
- 但在Python中使用DuckDB执行时,抛出错误:
duckdb.BinderException: Binder Error: Subquery returns 2 columns - expected 1 LINE 4: WHERE (first_name, age) IN (
测试数据:
customer_id first_name last_name age country 1 John Doe 31 USA 2 Robert Luna 22 USA 3 David Robinson 22 UK 4 John Reinhardt 25 UK 5 Betty Doe 28 UAE
报错的Python脚本:
import pandas as pd import duckdb conn = duckdb.connect('mydb.db') df = conn.execute(""" SELECT * FROM 'customer.csv' WHERE (first_name, age) IN ( SELECT first_name, min(age) FROM 'customer.csv' GROUP BY first_name ) """).df() print(df)
问题原因
该报错是DuckDB版本兼容性问题:旧版本的DuckDB不支持(列1,列2) IN (子查询返回多列)这种元组匹配的IN子查询语法,而部分在线SQL编译器使用的是PostgreSQL等支持该语法的引擎,因此可以正常运行。
替代实现方案
方案1:JOIN关联子查询(兼容所有SQL引擎)
通过JOIN关联分组后的最小age结果,是最通用的写法:
SELECT c.* FROM 'customer.csv' c JOIN ( SELECT first_name, MIN(age) AS min_age FROM 'customer.csv' GROUP BY first_name ) sub ON c.first_name = sub.first_name AND c.age = sub.min_age
方案2:窗口函数(高效且灵活)
使用窗口函数标记每个分组内的最小age记录,适合大数据量场景:
SELECT * FROM ( SELECT *, -- 按first_name分组,按age升序排序,标记第一条为1 ROW_NUMBER() OVER (PARTITION BY first_name ORDER BY age ASC) AS rn FROM 'customer.csv' ) t WHERE rn = 1
注:如果存在多个同
first_name且同最小age的记录,ROW_NUMBER()会只保留每组的第一条;若要保留所有符合条件的记录,可替换为RANK()。
方案3:升级DuckDB版本
DuckDB的较新版本(如v0.7.0及以上)已经支持多列元组IN子查询语法,升级后原查询语句可直接正常运行。
内容的提问来源于stack exchange,提问作者Kucharsky
相关产品推荐
相关产品推荐

