8

我有这样的事情:

SELECT id, fruit, pip 
FROM   plant 
WHERE  COUNT(*) = 2;

我猜这个奇怪的查询是不言自明的。COUNT(*)这里的意思是表中的行数plant我的要求是,仅当表中的总行数 = 2 时,我才需要从指定字段中检索值。这不起作用,但是:invalid use of aggregate function COUNT

我不能做到这一点:

SELECT COUNT(*) as cnt, id, fruit, pip 
FROM   plant 
WHERE  cnt = 2;

一方面,它将输出的行数限制为 1,另一方面,它给出了相同的错误:invalid use of aggregate function.

我能做的是:

SELECT id, fruit, pip 
FROM   plant 
WHERE  (
        SELECT COUNT(*) 
        FROM   plant
       ) = 2;

但随后该子查询是重新运行的主要查询。我在这里展示了问题的较大部分的一个小示例,尽管我知道COUNT(*)给定示例中的附加子查询并不是那么大的开销。

编辑:我不知道为什么这个问题被否决了。COUNT(*)我试图从查询中的一个视图(一个临时表)中获取,这是一个具有 5 到 6 个连接和附加 where 子句的大型查询。将查询作为子查询重新运行以获取计数效率低下,我也可以看到瓶颈。

这是实际的查询:

SELECT U.UserName, E.Title, AE.Mode, AE.AttemptNo, 
   IF(AE.Completed = 1, 'Completed', 'Incomplete'), 
   (
    SELECT COUNT(DISTINCT(FK_QId)) 
    FROM   attempt_question AS AQ
    WHERE  FK_ExcAttemptId = @excAttemptId
   ) AS Inst_Count, 
   (
    SELECT    COUNT(DISTINCT(AQ.FK_QId)) 
    FROM      attempt_question AS AQ
    JOIN      `question` AS Q 
          ON  Q.PK_Id = AQ.FK_QId                      
    LEFT JOIN actions AS A                             
           ON A.FK_QId = AQ.FK_QId
    WHERE     AQ.FK_ExcAttemptId = @excAttemptId
         AND (
                  Q.Type = @descQtn 
              OR  Q.Type = @actQtn 
              AND A.type = 'CTVI.NotImplemented'       
              AND A.IsDelete = @status                 
              AND (
                    SELECT COUNT(*) 
                    FROM   actions 
                    WHERE  FK_QId = A.FK_QId 
                       AND type != 'CTVI.NotImplemented'
                       AND IsDelete = @status
                   ) = 0
             )
   ) AS NotEvalInst_Count,  
   (
    SELECT COUNT(DISTINCT(FK_QId)) 
    FROM   attempt_question AS AQ
    WHERE  FK_ExcAttemptId = @excAttemptId 
       AND Mark = @mark
   ) AS CorrectAns_Count, 
   E.AllottedTime, AE.TimeTaken
FROM   attempt_exercise AS AE
JOIN   ctvi_exercise_tblexercise AS E 
    ON AE.FK_EId = E.PK_EId
JOIN   ctvi_user_table AS U 
    ON AE.FK_UId = U.PK_Id
JOIN   ctvi_grade AS G 
    ON AE.FK_GId = G.PK_GId
WHERE  AE.PK_Id = @excAttemptId
-- AND COUNT(AE.*) = @number --the portion in contention.

请忽略上述查询,并从我发布的小示例查询中引导我走向正确的方向,谢谢。

4

3 回答 3

7

在 MySQL 中,您只能执行您尝试过的操作:

SELECT id, fruit, pip 
FROM   plant 
WHERE  (
        SELECT COUNT(*) 
        FROM   plant
       ) = 2;

或这种变化:

SELECT id, fruit, pip 
FROM   plant 
  JOIN
      (
        SELECT COUNT(*) AS cnt 
        FROM   plant
       ) AS c
    ON c.cnt = 2;

第一个或第二个更有效,取决于 MySQL 的版本(和优化器)。我会打赌第二个,在大多数版本上。

在其他具有窗口函数的 DBMS 中,您还可以执行@Andomar 建议的第一个查询。


这是避免两次计算派生表的瓶颈的建议,一次获取行,一次获取计数。如果派生表的计算成本很高,并且它的行数为数千或数百万,那么计算它们两次只是为了丢弃它们,确实是一个问题。这可能会提高效率,因为它将中间(两次)计算的行限制为 3:

SELECT  p.*
FROM
    ( SELECT id, fruit, pip 
      FROM   plant 
      LIMIT 3
    ) AS p
  JOIN
    ( SELECT COUNT(*) AS cnt
      FROM   
        ( SELECT 1 
          FROM   plant 
          LIMIT 3
        ) AS tmp
    ) AS c
    ON c.cnt = 2 ;
于 2012-10-28T10:32:05.960 回答
5

重新阅读您的问题后,您仅在整个表中有 2 行时才尝试返回行。在那种情况下,我认为您自己的示例查询已经是最好的了。

在另一个 DBMS 上,您可以使用 Windowing 函数:

select  *
from    (
        select  *
        ,       count(*) over () as cnt
        from    plant
        ) as SubQueryAlias
where   cnt = 2

但是overMySQL 不支持该子句。

下面是旧的错误分析器

where子句在分组之前起作用。它适用于单行,而不是行组,因此您不能在子句中使用countor之类的聚合。maxwhere

要设置对行组起作用的过滤器,请使用该having子句。它在分组后工作,可用于过滤聚合:

SELECT id, fruit, pip 
FROM   plant 
GROUP BY
       id, fruit, pip 
HAVING COUNT(*) = 2;
于 2012-10-28T09:25:26.067 回答
1

其他答案不满足“不使用子查询”过滤结果的原始问题。

实际上,您可以通过在 2 个连续的 MySQL 语句中使用变量来执行此操作:

SET @count=0;

SELECT * FROM
(
    SELECT id, fruit, pip, @count:=@count+1 AS count
    FROM   plant 
    WHERE
) tmp
WHERE @count = 2;
于 2016-01-16T01:46:35.317 回答