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

子查询返回多行问题求助:如何计算生产操作时间占比?

解决SQL计算调整后占比(PCT)的问题

Hey there! 看你为这个结果集的问题折腾好久了,我来帮你梳理下思路,应该能解决你的困扰~

首先明确你的核心需求:

  • 要展示ProdOp、OpSUM(每个操作的时长)
  • 计算PCT:用总时长减去ProdOp='LL'的时长得到调整后总时长,再用每个OpSUM除以这个调整后总时长,转成百分比(比如你的示例里BB的20分钟占比4.2%)

你提到的子查询返回多行的问题,大概率是因为子查询没做单值聚合——如果子查询返回了多条记录,和主查询关联时就会出错或者得到不符合预期的结果。下面给你两种靠谱的解决方法:

方法1:用标量子查询获取调整后总时长

这种方法适合大多数SQL数据库(MySQL、PostgreSQL、SQL Server都支持),核心是让子查询只返回1行1列的单值:

SELECT
  ProdOp,
  OpSUM,
  -- 计算百分比,先把时间转成数值避免类型错误,保留1位小数
  ROUND(
    -- 把OpSUM转成分钟数(如果是INTERVAL类型)
    (EXTRACT(EPOCH FROM OpSUM) / 60) 
    / 
    -- 调整后总时长:总时长 - LL的时长,同样转成分钟数
    (
      (SELECT EXTRACT(EPOCH FROM SUM(TimeSUM))/60 FROM your_table)
      -
      (SELECT EXTRACT(EPOCH FROM SUM(TimeSUM))/60 FROM your_table WHERE ProdOp = 'LL')
    ) * 100,
    1
  ) AS PCT
FROM your_table
WHERE ProdOp != 'LL' -- 排除LL本身,和你的示例一致
ORDER BY ProdOp;

关键点:

  • 两个子查询都用SUM(TimeSUM)做聚合,确保只返回一个总时长值,不会出现多行的问题
  • 如果你的TimeSUM是数值类型(比如直接存分钟数),可以去掉EXTRACT(EPOCH ...)的转换,直接用数值计算

方法2:用CTE+交叉连接复用总时长

如果需要多次用到调整后总时长,用CTE(公共表表达式)先计算好,再通过交叉连接把这个全局值和每一行数据关联:

-- 先计算调整后的总时长,存在CTE里
WITH adjusted_total AS (
  SELECT
    (EXTRACT(EPOCH FROM SUM(TimeSUM))/60) 
    - 
    (EXTRACT(EPOCH FROM SUM(CASE WHEN ProdOp = 'LL' THEN TimeSUM ELSE 0 END))/60)
    AS total_minutes
  FROM your_table
)
SELECT
  t.ProdOp,
  t.OpSUM,
  ROUND(
    (EXTRACT(EPOCH FROM t.OpSUM)/60) / at.total_minutes * 100,
    1
  ) AS PCT
FROM your_table t
-- 交叉连接让每一行都能拿到总时长
CROSS JOIN adjusted_total at
WHERE t.ProdOp != 'LL'
ORDER BY t.ProdOp;

为什么交叉连接可行?

因为adjusted_total这个CTE只返回1行数据,交叉连接后不会产生笛卡尔积,反而能让每个ProdOp都复用同一个总时长值,完美贴合你之前考虑的交叉连接思路~

排查你之前的问题

如果之前的子查询返回多行,大概率是这两个原因:

  1. 子查询没加SUM()聚合,比如直接写SELECT TimeSUM FROM your_table WHERE ProdOp='LL',如果有多个LL的行就会返回多条
  2. 子查询的过滤条件不对,导致返回了多个分组的结果

按照上面的方法,确保总时长的计算是单值聚合,就不会出现多行的问题啦~

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.22 10:10:15