MySql获得最好的"通过选择在每个组中排

时间:2016-01-15 19:43:54

标签: mysql sql

我有一个包含5000行的数据库,其中包含人员,他们有数据及其结果,如下所示:

Table_A
+------+-------+-----+--------+
| Name | team  |r_id | result |
+------+-------+-----+--------+
| Jhon | A     | 1   | 12.45  |
| Mike | C     | 1   | 12.42  |
| Bob  | C     | 1   | 13.02  |
| ...  | ...   | ... | ...    |
| Alan | F     | 1   | 12.53  |
| ...  | ...   | ... | ...    |
| Mac  | A     | 2   | 5.24   |
| Josh | B     | 2   | 3.56   |
| Alan | F     | 2   | 4.12   |
| ...  | ...   | ... | ...    |
| Nic  | D     | 197 | 6.28   |
| Eli  | E     | 197 | 7.21   |
+------+-------+-----+--------+

另外还有另一个表,rid列是param1的中介(必须是)。

Table_B
+-----+--------+----------+
|r_id | param1 | fooData  |
+-----+--------+----------+
|   1 |      1 | A        |
|   2 |      3 | B        |
|   3 |      4 | A        |      two r_id set can have the same param1
|   4 |      4 | B        |
|   5 |      2 | C        |
|   6 |      3 | A        |
|   7 |      1 | B        |
+-----+--------+----------+

我需要使用"选择&#34 ;.

返回每个组中最好的

例如,

SELECT *
FROM Table_A a
LEFT JOIN Table_B b ON a.r_id = b.r_id
ORDER BY IF(b.fooData="A",CAST(result AS DECIMAL(4,3)),myCastFunction(result)) ASC
LIMIT 1

那个函数,用给定的数字(param1)命令每个组内的人,我希望第一行总是按每个组一起,显然是一个很好的表现。

+-------+------+-------+--------+
| group | Name | team  | result |
+-------+------+-------+--------+
| 1     | Mike | C     | 12.42  |
| 3     | Josh | B     | 3.56   |
| ...   | ...  | ...   | ...    |
| 194   | Nic  | D     | 6.28   |
+-------+------+-------+--------+

3 个答案:

答案 0 :(得分:2)

模式(MySQL v5.7)

CREATE TABLE table_a (
  `Name` VARCHAR(4),
  `team` VARCHAR(1),
  `r_id` INTEGER,
  `result` FLOAT
);

INSERT INTO table_a
  (`Name`, `team`, `r_id`, `result`)
VALUES
  ('Jhon', 'A', '1', '12.45'),
  ('Mike', 'C', '1', '12.42'),
  ('Bob', 'C', '1', '13.02'),
  ('Alan', 'F', '1', '12.53'),
  ('Mac', 'A', '2', '5.24'),
  ('Josh', 'B', '2', '3.56'),
  ('Alan', 'F', '2', '4.12'),
  ('Nic', 'D', '197', '6.28'),
  ('Eli', 'E', '197', '7.21');



CREATE TABLE table_b (
  `r_id` INTEGER,
  `param1` INTEGER,
  `fooData` VARCHAR(1)
);

INSERT INTO table_b
  (`r_id`, `param1`, `fooData`)
VALUES
  ('1', '1', 'A'),
  ('2', '3', 'B'),
  ('3', '4', 'A'),
  ('4', '4', 'B'),
  ('5', '2', 'C'),
  ('6', '3', 'A'),
  ('7', '1', 'B');

原始查询

SELECT *
FROM table_a a
LEFT JOIN table_b b ON a.r_id = b.r_id
ORDER BY IF(b.fooData="A",CAST(result AS DECIMAL(4,3)),SIN(result)) ASC
LIMIT 1;

| Name | team | r_id | result | r_id | param1 | fooData |
| ---- | ---- | ---- | ------ | ---- | ------ | ------- |
| Mac  | A    | 2    | 5.24   | 2    | 3      | B       |

查询#2

SELECT ab.*
FROM (
  SELECT a.*,
         b.param1,
         (
           @rn := IF(b.param1 = @g, @rn + 1, IF(@g := b.param1, 1, 1) )
         ) AS rn
  FROM table_a a 
  JOIN table_b b ON a.r_id = b.r_id 
  CROSS JOIN (
    SELECT @g := '', @rn := 0
  ) params
  ORDER BY b.param1, IF(b.fooData="A",CAST(result AS DECIMAL(4,3)),SIN(result)) ASC
) ab
WHERE rn = 1;

| Name | team | r_id | result | param1 | rn  |
| ---- | ---- | ---- | ------ | ------ | --- |
| Jhon | A    | 1    | 12.45  | 1      | 1   |
| Mac  | A    | 2    | 5.24   | 3      | 1   |

View on DB Fiddle

答案 1 :(得分:0)

您需要联接才能识别这些群组。然后你需要一些方法来选择第一行。我会选择变量:

select ab.*
from (select a.*, b.grp,
             (@rn := if(b.grp = @g, @rn + 1,
                        if(b.grp := @g, 1, 1)
                       )
             ) as rn
      from table_a a join
           table_b b
           on a.r_id = b.r_id cross join
           (select @g := '', @rn := 0) params
      order by b.grp, a.result
     ) ab
where rn = 1;

答案 2 :(得分:0)

由于mysql不支持分区,最简单的方法可能是使用table_a中的subselect:

select a.* from
    (select distinc group from table_b) grp
    inner join table_a a
        on a.r_id in (select b.r_id from table_b b where b.group = grp.group) and
        result = (
            select min(result) from table_a ai where
                ai.r_id in (select b.r_id from table_b b where b.group = grp.group)
        )