我有这样的事情:
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,它将输出的行数限制为1和2,它给出了相同的错误: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.
请忽略上述查询,并引导我从我发布的小示例查询中找到正确的方向,谢谢。
答案 0 :(得分: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 ;
答案 1 :(得分:5)
重新阅读问题后,只有在整个表格中有2行时才会尝试返回行。在这种情况下,我认为您自己的示例查询已经是最好的了。
在另一个DBMS上,您可以使用窗口函数:
select *
from (
select *
, count(*) over () as cnt
from plant
) as SubQueryAlias
where cnt = 2
但MySQL不支持over
子句。
旧的错误的anser
where
子句在分组之前有效。它适用于单行,而不适用于行组,因此您无法在count
子句中使用max
或where
等聚合。
要设置适用于行组的过滤器,请使用having
子句。它在分组后有效,可用于过滤聚合:
SELECT id, fruit, pip
FROM plant
GROUP BY
id, fruit, pip
HAVING COUNT(*) = 2;
答案 2 :(得分:1)
其他答案不符合原始问题,即在不使用子查询的情况下过滤结果。
您实际上可以通过在2个连续的MySQL语句中使用变量来实现此目的:
SET @count=0;
SELECT * FROM
(
SELECT id, fruit, pip, @count:=@count+1 AS count
FROM plant
WHERE
) tmp
WHERE @count = 2;