我有一张类似于以下内容的表格:
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个最小到期的查询。例如,对于n = 2,我希望:
date | expiry
-------------------------
2010-01-01 | 2010-03-02
2010-02-01 | 2010-04-02
我的麻烦是AFAIK,没有聚合函数返回第n个最大/最小元素,所以我不能使用'GROUP BY'。更具体地说,如果我有一个神奇的MIN()聚合接受第二个参数'offset',我会写:
SELECT MIN(expiry, 1) FROM table WHERE date IN ('2010-01-01', '2010-02-01') GROUP BY date
有什么建议吗?
答案 0 :(得分:10)
一个hack是使用group_concat。按日期分组并按升序排列到期日期,并使用substring_index函数获取第n个值。
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 | edate |
+------------+----------------------------------+
| 2010-01-01 | 2010-02-01,2010-03-02,2010-04-04 |
| 2010-02-01 | 2010-03-01,2010-04-02 |
+------------+----------------------------------+
substring_index(edate,',',2)向前传递2个元素(对于第n个元素用2替换为n)。
+------------+------------------------------+
| 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(substring_index(edate,',',2),',', - 1)
+------------+------------------------------------------------------+
| mdate | substring_index(substring_index(edate,',',2),',',-1) |
+------------+------------------------------------------------------+
| 2010-01-01 | 2010-03-02 |
| 2010-02-01 | 2010-04-02 |
+------------+------------------------------------------------------+
如果要连接的值太多,则可能会超出group_concat_max_len值(默认为1024,但可以设置得更高)。
更新:即使该组中的n个元素较少,上面给出的SQL也会给出第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;
答案 1 :(得分:0)
我建议您使用n值并使用它来控制返回大小。 例如,假设您想要第三低的价值...... 你真正追求的是底部3值的最大值
所以它将是TOP 1 FROM(TOP n ORDER BY col ASC)
编辑:如@Chad Birch的评论中所述,如果您无法在子查询中使用LIMIT,则此方法可能会出现问题。 EDIT2:
以下是使用JOIN
和LIMIT
的有趣解决方法
http://lists.mysql.com/mysql/211239