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 つは、出力される行数を 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.

上記のクエリを無視して、私が投稿した小さなクエリの例から正しい方向に導いてください。

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;

1 番目と 2 番目のどちらが効率的かは、MySQL (およびオプティマイザ) のバージョンによって異なります。ほとんどのバージョンで、2番目のものに賭けます。

ウィンドウ関数を持つ他の DBMS では、@Andomar が提案する最初のクエリを実行することもできます。


派生テーブルを 2 回計算するボトルネックを回避するための提案を次に示します。1 回目は行を取得し、もう 1 回はカウントを取得します。派生テーブルの計算コストが高く、その行数が数千または数百万の場合、それらを 2 回計算して破棄するだけでは、実際問題になります。これにより、中間 (2 回) に計算される行が 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 では、ウィンドウ関数を使用できます。

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

ただし、このover節は MySQL ではサポートされていません。

下の古い間違ったアンサー

このwhere句は、グループ化の前に機能します。行のグループではなく、単一の行で機能するため、句のようcountな集計を使用することはできません。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 に答える