You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.13 21:06:17