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

如何在Knex.js中对UNION ALL查询的第一个表达式使用GROUP BY?

解决Knex.js中UNION ALL导致GROUP BY位置错误的问题

问题场景

现有entries表与categories表通过category_id关联,entries表包含BOOLEAN类型的is_marked字段。需求是统计两类数据并合并结果:

  • 每个分类下的条目数量
  • 所有标记为is_marked = 1的条目总数

计划用UNION ALL实现,预期生成的SQL如下:

(
SELECT 
    cat.category_name AS `name`, 
    cat.category_id AS `id`, 
    COUNT(DISTINCT e.entry_id) AS `entry_count` 
FROM `categories` AS `cat` 
    INNER JOIN `entries` AS `e` USING (category_id)
GROUP BY cat.category_name
) UNION ALL (
SELECT
    "Marked Entry" AS `name`, 
    -1 AS `id`, 
    COUNT(DISTINCT e2.entry_id) AS `entry_count` 
 FROM `entries` AS `e2` 
    WHERE `e2`.`is_marked` = 1
)

但原Knex代码生成的SQL错误地将GROUP BY放到了UNION ALL之后,触发MySQL 1140错误,生成的错误SQL如下:

select 
    `cat`.`category_name` as `name`, 
    `cat`.`category_id` as `id`, 
    count(distinct `e`.`entry_id`) as `entry_count` 
from `categories` as `cat` 
    inner join `entries` as `e`
    on `e`.`category_id` = `cat`.`category_id`
union all
select
    "Marked Entry" AS `name`, 
    -1 AS `id`, 
    count(distinct `e2`.`entry_id`) as `entry_count` 
from `entries` as `e2`
    where `e2`.`is_marked` = ?
group by `cat`.`category_name`

解决方案

使用Knex的wrap()方法,将每个子查询用括号包裹,强制GROUP BY仅作用于第一个子查询。修改后的Knex代码如下:

const categoryQuery = knex
    .select('cat.category_name AS name', 'cat.category_id AS id')
    .countDistinct('e.entry_id AS entry_count')
    .from('categories AS cat')
    .innerJoin('entries AS e', 'e.category_id', 'cat.category_id')
    .groupBy('cat.category_name')
    .wrap('(', ')'); // 给第一个子查询添加括号

const markedQuery = knex
    .select(knex.raw('"Marked Entry" AS `name`'), knex.raw('-1 AS `id`'))
    .countDistinct('e2.entry_id AS entry_count')
    .from('entries AS e2')
    .where('e2.is_marked', '=', 1)
    .wrap('(', ')'); // 给第二个子查询添加括号

const finalQuery = categoryQuery.unionAll([markedQuery]);

原理说明

Knex默认生成的UNION ALL不会自动给子查询添加括号,导致GROUP BY被提升到整个联合查询的外层。通过wrap('(', ')')方法,让每个子查询都被独立包裹,确保GROUP BY只属于第一个子查询,生成的SQL会与预期一致。

内容的提问来源于stack exchange,提问作者LeCarbonator

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.01 02:10:32