【问题标题】:error : subquery must return only one column错误:子查询必须只返回一列
【发布时间】:2013-11-08 01:41:19
【问题描述】:

我在尝试运行以下查询时收到错误 subquery must return only one column

SELECT mat.mat as mat1, sum(stx.total ) as sumtotal1,
  (
    SELECT mat.mat  as mat, sum(stx.total)  as sumtotal
    FROM stx 
      LEFT JOIN mat ON stx.matid = mat.matid
      LEFT JOIN sale ON stx.saleid = sale.id
    WHERE stx.date BETWEEN '2013-05-01' AND '2013-08-31' 
      AND sale.userid LIKE 'A%'
    GROUP BY mat.mat
) AS MyField
FROM stx 
  LEFT JOIN mat ON stx.matid = mat.matid
  LEFT JOIN sale ON stx.saleid = sale.id
WHERE stx.date BETWEEN '2013-05-01' AND '2013-08-31'
  AND sale.userid LIKE 'B%'
GROUP BY mat.mat

是什么导致了这个错误?

【问题讨论】:

  • @user2431581,您正在通过子查询定义字段 MyField。当您这样做时,子查询必须只返回一个值和一个字段。您将返回 mat.matsum(stx.total)。那是非法的 SQL 语法。

标签: sql postgresql join left-join cross-join


【解决方案1】:

代替子查询选择语句

SELECT mat.mat  as mat, sum(stx.total)  as sumtotal

试试这个说法

SELECT sum(stx.total)  as sumtotal

【讨论】:

  • 试试这个语句 SELECT sum(stx.total) as sumtotal ERROR: more than one row returned by a subquery used as an expression
【解决方案2】:

FROM 列表中放置一个返回多列的子查询并从中进行选择。

开始时关联子查询是个坏主意。但是,您的查询甚至不相关,而是不相关(没有指向外部查询的链接)并且似乎返回多行。这会导致(可能非常昂贵且荒谬)交叉连接产生笛卡尔积,可能不是您的(秘密)意图。

看起来你真的很想要:

SELECT m1.mat AS mat1, m1.sumtotal AS sumtotal1
      ,m2.mat AS mat2, m2.sumtotal AS sumtotal2
FROM (
   SELECT mat.mat, sum(stx.total) AS sumtotal
   FROM   stx 
   LEFT   JOIN mat ON mat.matid = stx.matid
   LEFT   JOIN sale ON stx.saleid = sale.id
   WHERE  stx.date BETWEEN '2013-05-01' AND '2013-08-31'
   AND    sale.userid LIKE 'A%'
   GROUP  BY mat.mat
   ) m1
JOIN  (
   SELECT mat.mat, sum(stx.total) AS sumtotal
   FROM   stx 
   LEFT   JOIN mat ON mat.matid = stx.matid
   LEFT   JOIN sale ON sale.id = stx.saleid
   WHERE  stx.date BETWEEN '2013-05-01' AND '2013-08-31' 
   AND    sale.userid LIKE 'b%'
   GROUP  BY mat.mat
   ) m2 USING (mat);

LEFT JOIN 也毫无意义。 sale 上的那个被 WHERE 条件强制为 INNER JOIN。垫子上的那个似乎毫无意义,因为你 GROUP BY mat.mat - 除非你对 mat IS NULL 感兴趣? (我怀疑。)

这个案例大概可以进一步简化为:

SELECT m.mat
      ,sum(CASE WHEN s.userid LIKE 'A%' THEN x.total END) AS total_a
      ,sum(CASE WHEN s.userid LIKE 'B%' THEN x.total END) AS total_b
FROM   sale s 
JOIN   stx  x ON x.saleid = s.id
JOIN   mat  m ON m.matid = x.matid
WHERE (s.userid LIKE 'A%' OR s.userid LIKE 'B%')
AND    x.date BETWEEN '2013-05-01' AND '2013-08-31'
GROUP  BY 1;

WHERE 条件可能可以进一步简化,具体取决于您的秘密数据类型和索引。 this related answer on dba.SE 中有大量关于该案例的信息。

【讨论】:

  • "在 FROM 列表中放置一个返回多列的子查询并从中选择。".这!非常感谢。
  • 如果 select 是针对具有多个 OUT 参数的函数执行的(但该函数不返回记录、setof 或任何类似类型并且该函数无法更改)怎么办?例如,假设一个函数有 2 个输出参数,'hi' 和 'lo'——因此常规使用会返回一个像 (4, 5) 这样的记录元组。但是“select *”会将结果分别返回为两列。现在假设您想在某个连接结果的多个列上执行该函数。类似select my_func(a.colA, b.colB) from tabA a join tabB b on a.id = b.id.
  • @Mr.F:这超出了评论范围。我建议您使用必要的信息开始一个新问题。您可以随时链接到这个以供参考,并发表评论以链接到相关问题并通知我。有一个解决方案...
  • 好建议。这是link to the question
  • 不错的解决方案救了我的脖子谢谢兄弟
猜你喜欢
  • 2019-12-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-01-01
  • 1970-01-01
  • 2019-11-10
相关资源
最近更新 更多