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

如何在循环中以编程方式添加UNION ALL拼接多段SELECT?

如何用Laravel Query Builder构建带UNION ALL的多SELECT查询(最后一个不含UNION ALL)

你的需求与问题

我需要构建如下结构的SQL查询:

SELECT 
...
FROM table
WHERE
...
GROUP BY
...
UNION ALL

SELECT 
...
FROM table
WHERE
...
GROUP BY
...
UNION ALL

SELECT 
...
FROM table
WHERE
...
GROUP BY
...
.. 以此类推..

我从数组中获取数据,通过foreach循环逐个构建每个SELECT语句,并希望在每个SELECT后添加UNION ALL(最后一个除外)。
但我无法实现这一逻辑,当前尝试的代码如下:

$query = DB::table('table');
foreach ($data as $item) {
    $query->.. // 构建SELECT语句

    $query->unionAll($query); // 无法正常工作
}

补充:以下是我实际使用的更准确代码:

$query = DB::table('table');

foreach ($data as $item) {
    foreach ($item as $key => $value) {
        if (in_array($key, $info)) {
            $query->addSelect($key);
        }
    }

    $query->selectRaw("COUNT(CASE...)");
    $query->selectRaw("COUNT(CASE...)");

    foreach ($item as $key => $value) {
        if (in_array($key, $info)) {
            $query->where($key, "=", $value);
        }
    }

    foreach ($item as $key => $value) {        
        $query->addSelect($key);     
    } 

    foreach ($item as $key => $value) {        
        $query->groupBy($key);     
    } 
}

问题根源

你当前的写法有两个核心问题:

  1. 一直在同一个Query Builder实例上叠加操作,导致所有SELECT、WHERE、GROUP BY都合并成了一个查询,根本没生成多个独立的SELECT语句
  2. $query->unionAll($query)是把当前查询和自身合并,形成循环引用,完全不符合你要拼接多个不同子查询的需求

正确实现方案

我们需要为数组里的每个$item创建独立的Query Builder实例,再把这些实例用unionAll依次连接起来,最后执行最外层的查询。

1. 初始化数组存储所有独立子查询

$queries = [];

2. 遍历$data,为每个$item创建单独的查询

foreach ($data as $item) {
    // 关键:每个item都新建一个Query Builder实例,和其他查询完全独立
    $subQuery = DB::table('table');

    // 添加需要SELECT的字段(根据你的业务逻辑)
    foreach ($item as $key => $value) {
        if (in_array($key, $info)) {
            $subQuery->addSelect($key);
        }
    }

    // 添加统计类的selectRaw字段(记得补全CASE里的逻辑)
    $subQuery->selectRaw("COUNT(CASE WHEN ... THEN 1 END) as total_valid");
    $subQuery->selectRaw("COUNT(CASE WHEN ... THEN 1 END) as total_invalid");

    // 补充其他需要SELECT的字段
    foreach ($item as $key => $value) {        
        $subQuery->addSelect($key);     
    } 

    // 构建WHERE条件
    foreach ($item as $key => $value) {
        if (in_array($key, $info)) {
            $subQuery->where($key, "=", $value);
        }
    }

    // 构建GROUP BY
    foreach ($item as $key => $value) {        
        $subQuery->groupBy($key);     
    } 

    // 把当前子查询存入数组
    $queries[] = $subQuery;
}

3. 合并所有子查询,自动处理UNION ALL(最后一个不加)

if (empty($queries)) {
    // 处理$data为空的情况,返回空集合即可
    $result = collect();
} else {
    // 拿第一个查询作为基础
    $finalQuery = $queries[0];

    // 从第二个查询开始,逐个添加UNION ALL
    for ($i = 1; $i < count($queries); $i++) {
        $finalQuery->unionAll($queries[$i]);
    }

    // 执行查询,获取结果
    $result = $finalQuery->get();
}

核心要点

  • 独立实例:每个子查询必须是全新的DB::table()实例,这样各个SELECT/WHERE/GROUP BY才不会互相干扰
  • 数组存储+循环合并:通过数组收集所有子查询,再从第二个开始逐个unionAll,完美实现"最后一个不加UNION ALL"的需求
  • 边界处理:别忘了判断$data为空的情况,避免出现报错

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.04 16:35:13