6

在 Mysql 中,我想从每个类别中选择底部的 2 个项目

Category Value
1        1.3
1        4.8
1        3.7
1        1.6
2        9.5
2        9.9
2        9.2
2        10.3
3        4
3        8
3        16

给我:

Category Value
1        1.3
1        1.6
2        9.5
2        9.2
3        4
3        8

在我从 sqlite3 迁移之前,我必须首先从每个类别中选择一个最低的,然后排除任何加入该类别的东西,我必须再次从每个类别中选择最低的。然后任何等于或小于一个类别中新的最低值的东西都赢了。如果出现平局,这也会选择超过 2 个,这很烦人......它的运行时间也很长。

我的最终目标是计算一个人在一个类别的最低 2 之一中的次数(还有一个名称字段),这是我不知道该怎么做的一部分。谢谢

4

5 回答 5

8
SELECT c1.category, c1.value
FROM catvals c1
LEFT OUTER JOIN catvals c2
  ON (c1.category = c2.category AND c1.value > c2.value)
GROUP BY c1.category, c1.value
HAVING COUNT(*) < 2;

使用您的测试数据在 MySQL 5.1.41 上进行了测试。输出:

+----------+-------+
| category | value |
+----------+-------+
|        1 |  1.30 |
|        1 |  1.60 |
|        2 |  9.20 |
|        2 |  9.50 |
|        3 |  4.00 |
|        3 |  8.00 |
+----------+-------+

(额外的小数位是因为我将该value列声明为NUMERIC(9,2)。)

与其他解决方案一样,如果存在平局,则每个类别会产生超过 2 行。有一些方法可以构建连接条件来解决这个问题,但我们需要在您的表中使用主键或唯一键,并且我们还必须知道打算如何解决关系。

于 2009-12-17T19:21:56.820 回答
4

你可以试试这个:

SELECT * FROM (
  SELECT c.*,
        (SELECT COUNT(*)
         FROM user_category c2
         WHERE c2.category = c.category
         AND c2.value < c.value) cnt
  FROM user_category c ) uc
WHERE cnt < 2

它应该会给您想要的结果,但请检查性能是否正常。

于 2009-12-17T18:46:04.043 回答
1

工会应该工作。与彼得的解决方案相比,我不确定性能。

SELECT smallest.category, MIN(smallest.value)
    FROM categories smallest
GROUP BY smallest.category
UNION
SELECT second_smallest.category, MIN(second_smallest.value)
    FROM categories second_smallest
    WHERE second_smallest.value  > (SELECT MIN(smallest.value) FROM categories smallest WHERE second.category = second_smallest.category)
GROUP BY second_smallest.category
于 2009-12-17T18:49:21.117 回答
1

这是一个非常通用的解决方案,适用于为每个类别选择前 n 行。即使有重复值,这也将起作用。

/* creating temporary variables */
mysql> set @cnt = 0;
mysql> set @trk = 0;

/* query */
mysql> select Category, Value 
       from (select *, 
                @cnt:=if(@trk = Category, @cnt+1, 0) cnt, 
                @trk:=Category 
                from user_categories 
                order by Category, Value ) c1 
       where c1.cnt < 2;

这是结果。

+----------+-------+
| Category | Value |
+----------+-------+
|        1 |   1.3 |
|        1 |   1.6 |
|        2 |   9.2 |
|        2 |   9.5 |
|        3 |     4 |
|        3 |     8 |
+----------+-------+

这是在 MySQL 5.0.88 上测试的。注意 @trk 变量的初始值不应该是 Category 字段的最小值。

于 2009-12-17T19:24:32.680 回答
1

这是一个正确处理重复项的解决方案。表名是“zzz”,列是 int 和 float

select
    smallest.category category, min(smallest.value) value
from 
    zzz smallest
group by smallest.category

union

select
    second_smallest.category category, min(second_smallest.value) value
from
    zzz second_smallest
where
    concat(second_smallest.category,'x',second_smallest.value)
    not in ( -- recreate the results from the first half of the union
        select concat(c.category,'x',min(c.value))
        from zzz c
        group by c.category
    )
group by second_smallest.category

order by category

注意事项:

  • 如果给定类别只有一个值,则仅返回该单个条目。
  • 如果每一行都有一个唯一的记录 ID,那么您就不需要所有的连接来模拟一个唯一的键。

你的旅费可能会改变,

- 标记

于 2009-12-17T19:26:31.803 回答