2009-06-11 29 views
4

、GROUP BYを使用した場合、誤った行を示しています。チケットはサポートスタッフと顧客の間で電子メールのスレッドを表し、記事がスレッドを構成する個々のメッセージですMYSQLは、私は2つのテーブルを持っている

article('id', 'ticket_id', 'incoming_time', 'to', 'from', 'message') 
ticket('id', 'queue_id') 

私は、各TICKET_IDのために(UNIXタイムスタンプとして表される)最高の着信時間との記事を見つけるために探しています、これは私が現在使用しているクエリです:

SELECT article.* , MAX(article.incoming_time) as maxtime 
FROM ticket, article 
WHERE ticket.id = article.ticket_id 
AND ticket.queue_id = 1 
GROUP BY article.ticket_id 

例えば、

:article: 
id --- ticket_id --- incoming_time --- to ------- from ------- message -------- 
11  1    1234567   [email protected]  [email protected]  I need help... 
12  1    1235433   [email protected] [email protected]  How can we help? 
13  1    1240321   [email protected]  [email protected]  Want food!  
... 

:ticket: 
id --- queue_id 
1  1 
... 

しかし、結果ではなく、私は最高の着信時間との記事であるために探しているものの最小の文書番号と列になりそうです。

アドバイスをいただければ幸いです!

答えて

16

これは、ほとんどのMySQLプログラマが突き当たる古典的なハードルです。

  • GROUP BYの引数である列ticket_idがあります。この列の明確な値はグループを定義します。
  • MAX()の引数である列incoming_timeがあります。各グループの行に対するこの列の最大値は、MAX()の値として返されます。
  • 他のすべての表の記事の列があります。 これらの列に対して返される値は任意であり、MAX()値が出現する同じ行からではありません。

データベースでは、最大値が発生する同じ行の値が必要であると推測することはできません。

は、次の例について考えてみよう:

  • 同じ最大値が発生し、複数の行があります。 article.*の列を表示するためにどの行を使用する必要がありますか?

  • MIN()MAX()の両方を返すクエリを作成します。これは合法ですが、どちらの行をarticle.*に表示する必要がありますか?いいえ行がその値を有していないようなAVG()又はSUM()として集計関数を使用

    SELECT article.* , MIN(article.incoming_time), MAX(article.incoming_time) 
    FROM ticket, article 
    WHERE ticket.id = article.ticket_id 
    AND ticket.queue_id = 1 
    GROUP BY article.ticket_id 
    
  • 。データベースはどの行を表示するかを推測する方法は?だけでなく、SQL標準自体 - - ほとんどのデータベースのブランドで

    SELECT article.* , AVG(article.incoming_time) 
    FROM ticket, article 
    WHERE ticket.id = article.ticket_id 
    AND ticket.queue_id = 1 
    GROUP BY article.ticket_id 
    

あなたがあるため曖昧で、はこのようなクエリを記述することはできません。選択リストには、集計関数内にないか、GROUP BY節で指定された列を含めることはできません。

MySQLはより許容されます。これにより、これを行うことができ、あいまいさなくクエリを書くことができます。あいまいさがある場合は、グループ内の物理的に最初の行から値を選択します(ただし、これはストレージエンジンまでです)。

SQLiteでもこの動作がありますが、あいまいさを解決するためにグループ内で最後の行が選択されています。 Go figure。 SQL標準が何をすべきかを言わないならば、それはベンダーの実装に依存します。言い換えれば

SELECT a1.* , a1.incoming_time AS maxtime 
FROM ticket t JOIN article a1 ON (t.id = a1.ticket_id) 
LEFT OUTER JOIN article a2 ON (t.id = a2.ticket_id 
    AND a1.incoming_time < a2.incoming_time) 
WHERE t.queue_id = 1 
    AND a2.ticket_id IS NULL; 

、同じticket_idおよび大きいと行(a1)そのため、他の行(a2)がないを探します。ここでは

はあなたのためにあなたの問題を解決することができ、クエリです incoming_timeincoming_timeが見つからない場合、LEFT OUTER JOINは一致するのではなくNULLを返します。

+0

チャームのように働いていて、答えは非常によく説明されました。 – Han

3
SELECT a1.* FROM article a1 
JOIN 
    (SELECT MAX(a2.incoming_time) AS maxtime 
    FROM article a2 
    JOIN ticket ON (a2.ticketid=ticket.id) 
    WHERE ticket.queue_id=1) xx 
    ON (a1.incoming_time=xx.maxtime); 
関連する問題