2011-01-26 11 views
10

における二最小要素:表でMySQLの私は、次のようなテーブルが各グループ

date | expiry 
-------------------------  
2010-01-01 | 2010-02-01 
2010-01-01 | 2010-03-02 
2010-01-01 | 2010-04-04 
2010-02-01 | 2010-03-01 
2010-02-01 | 2010-04-02 

、各日付は、複数の「有効期限」の値を有していてもよいです。私は各日付でn番目に最小の有効期限を返すクエリが必要です。

 date | expiry 
-------------------------  
2010-01-01 | 2010-03-02 
2010-02-01 | 2010-04-02 

私のトラブルは、私の知る限りでは、n番目の最大/最小の要素を返します。何の集約関数が存在しないということですので、私はBY」グループを使用することはできません:たとえば、のためのn = 2、私は期待します'私は「オフセット」二番目のパラメータを受け入れ魔法のMIN()集約を持っていた場合は具体的には、私が書くでしょう:

SELECT MIN(expiry, 1) FROM table WHERE date IN ('2010-01-01', '2010-02-01') GROUP BY date 

任意の提案を?

+0

絶対に1つのクエリ内で実行する必要がありますか? MySQLはサブクエリ内部で 'LIMIT'節をサポートしていないので、特に困難です。すべてを選択して実際にデータベースの外にあるレコードを探し出すのが最も簡単なことに終わることがあります。 @Chad Birch。 –

+0

選択肢がない場合は、提案したようにしますが、単一のMySqlクエリでそれを実行できるようにするには、要件が単純で有用であると感じています。私は間違っているかもしれない、タフ:-) – bavaza

+0

タグで 'グループごとの最高のn'。答えの中には、MySQLの欠けている機能に対処する一般的な方法があります。完全なグループセットを生成するものは選択可能でなければなりません。魔法のコードを見つけることを幸運。 –

答えて

9

一つハックとJOIN Sを使用して、興味深い問題を回避するには、GROUP_CONCATを使用することです。日付でグループ化し、有効期限を昇順で連結し、substring_index関数を使用してn番目の値を取得します。 (nでn番目の要素の代替2用)2つの素子進む(2 ''、EDATE)

+------------+----------------------------------+ 
| mdate  | edate       | 
+------------+----------------------------------+ 
| 2010-01-01 | 2010-02-01,2010-03-02,2010-04-04 | 
| 2010-02-01 | 2010-03-01,2010-04-02   | 
+------------+----------------------------------+ 

SUBSTRING_INDEX:例で

mysql> select * from expiry; 
+------------+------------+ 
| date  | expiry  | 
+------------+------------+ 
| 2010-01-01 | 2010-02-01 | 
| 2010-01-01 | 2010-03-02 | 
| 2010-01-01 | 2010-04-04 | 
| 2010-02-01 | 2010-03-01 | 
| 2010-02-01 | 2010-04-02 | 
+------------+------------+ 
5 rows in set (0.00 sec) 

mysql> SELECT mdate, 
     Substring_index(Substring_index(edate, ',', 2), ',', -1) AS exp_date 
FROM (SELECT `date`    AS mdate, 
       GROUP_CONCAT(expiry order by expiry asc separator ",") AS edate 
     FROM expiry 
     GROUP BY mdate) e1; 
+------------+------------+ 
| mdate  | exp_date | 
+------------+------------+ 
| 2010-01-01 | 2010-03-02 | 
| 2010-02-01 | 2010-04-02 | 
+------------+------------+ 
2 rows in set (0.00 sec) 

は、ここでは、サブ問合せは、次の出力を与えます。

+------------+------------------------------+ 
| mdate  | substring_index(edate,',',2) | 
+------------+------------------------------+ 
| 2010-01-01 | 2010-02-01,2010-03-02  | 
| 2010-02-01 | 2010-03-01,2010-04-02  | 
+------------+------------------------------+ 

我々はSUBSTRING_INDEX(SUBSTRING_INDEX(EDATE、 ''、2) '' 使用してのみ第2要素(中間結果の最後の要素)を取得し、上記出力に別のSUBSTRING_INDEXを実行 - 1そこにあなたがgroup_concat_max_len値(デフォルト1024が不足することがありますCONCATする、あまりにも多くの値がありますが、高く設定することができた場合)

+------------+------------------------------------------------------+ 
| mdate  | substring_index(substring_index(edate,',',2),',',-1) | 
+------------+------------------------------------------------------+ 
| 2010-01-01 | 2010-03-02           | 
| 2010-02-01 | 2010-04-02           | 
+------------+------------------------------------------------------+ 

)。

UPDATE:上記のSQLはthtグループのn個の要素が少なくてもn番目の要素を与えます。 SQLが次のように変更されるのを避けるために:

SELECT mdate, 
     IF(cnt >= 2,Substring_index(Substring_index(edate, ',', 2), ',', -1),NULL) AS exp_date 
FROM (SELECT `date`    AS mdate, 
       count(expiry) as cnt, 
       GROUP_CONCAT(expiry order by expiry asc separator ",") AS edate 
     FROM expiry 
     GROUP BY mdate) e1; 
0

あなたはn値を取って、あなたのリターンサイズを制御するために使用することをお勧めします。たとえば、あなたが後に実際にいる何 は、下の3つの値

から最大値であるので、それは

(TOP N ORDERコルASC BY)から、1 TOPだろう...あなたは3番目に低い値を望んでいた を言います

EDIT:@Chad Birchのコメントに記載されているように、サブクエリの内部でLIMITを使用できない場合は、この方法が問題になることがあります。

EDIT2: ここではLIMIT http://lists.mysql.com/mysql/211239

+0

MySQLのMSSQLの 'TOP'に相当するのは' LIMIT'節ですが、サブクエリではこれをサポートしていませんので、1つのクエリで行う必要がある場合はオプションではありません。 –

関連する問題