错误:子查询必须仅返回一列

问题描述 投票:0回答:2

当我尝试运行以下查询时,出现错误

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

导致此错误的原因是什么?

sql postgresql join left-join cross-join
2个回答
22
投票

将返回多列的子查询放入

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
上的那个被
INNER JOIN
条件强制变为
WHERE
mat
上的那个似乎毫无意义,因为你
GROUP BY mat.mat
- 除非你对
mat IS NULL
感兴趣? (我对此表示怀疑。)

整个查询可以进一步简化为:

SELECT m.mat
     , sum(x.total) FILTER (WHERE s.userid LIKE 'A%') AS total_a
     , sum(x.total) FILTER (WHERE s.userid LIKE 'B%') 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 'ANY ('{A%,B%}')
AND    x.date BETWEEN '2013-05-01' AND '2013-08-31'
GROUP  BY 1;

使用聚合

FILTER
子句(Postgres 9.4+)。参见:

在 Postgres 11 或更高版本中,可以使用 “starts with”运算符

^@
进一步优化前缀匹配。参见:

SELECT m.mat
     , sum(x.total) FILTER (WHERE s.userid ^@ 'A') AS total_a
     , sum(x.total) FILTER (WHERE s.userid ^@ 'B') 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 ^@ ANY ('{A,B}')  
AND    x.date BETWEEN '2013-05-01' AND '2013-08-31'
GROUP  BY 1;

WHERE
条件可能会变得更加简单,具体取决于您的秘密数据类型和索引。以下是模式匹配运算符的概述:


0
投票

代替子查询select语句

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

试试这个说法

SELECT sum(stx.total)  as sumtotal
© www.soinside.com 2019 - 2024. All rights reserved.