通过两个值的最小值从组中选择单个结果

时间:2015-08-07 12:41:30

标签: mysql sql

我有一个看起来像这样的表:

+----+-------+---------+--------+--------+
| id | meta1 | meta2   | value1 | value2 |
+----+-------+---------+--------+--------+
|  1 | foo   | bar     |    0.1 |   0.01 |
|  1 | baz   | quux    |    0.2 |   0.01 |
|  1 | lorem | ipsum   |    0.1 |   0.05 |
|  2 | dolor | sit     |    0.2 |   0.02 |
|  2 | amet  | eos     |    0.3 |   0.02 |
|  3 | clita | corpora |    0.5 |   0.03 |
+----+-------+---------+--------+--------+

我正在尝试为每个具有最低value1的ID提取一个(完整的)行,如果有相等的value1 s,则返回到最低值2.

查询应该产生如下结果集:

+----+-------+---------+--------+--------+
| id | meta1 | meta2   | value1 | VALUE2 |
+----+-------+---------+--------+--------+
|  1 | foo   | bar     |    0.1 |   0.01 |
|  2 | dolor | sit     |    0.2 |   0.02 |
|  3 | clita | corpora |    0.5 |   0.03 |
+----+-------+---------+--------+--------+

我首先尝试以下查询:

SELECT
    t1.*
FROM
    test t1
        INNER JOIN
    (SELECT
        id, MIN(value1) minValue1
    FROM
        test
    GROUP BY id) t2 ON t1.id = t2.id
        AND t1.value1 = t2.minValue1;

但这并没有为'1'打破“平局”,我最终得到了两条记录。我已经尝试添加HAVING子句和其他子查询,并且在此初始步骤之后丢失了。非常感谢。

3 个答案:

答案 0 :(得分:2)

您希望所有没有更好记录的记录(即具有较低的值1或相同的值1和较低的值2)存在:

select *
from mytable
where not exists
(
  select *
  from mytable better
  where better.id = mytable.id
  and 
  (
    better.value1 < mytable.value1
    or 
    (better.value1 = mytable.value1 and better.value2 < mytable.value2)
  )
);

答案 1 :(得分:1)

您可以使用not exists

SELECT t.*
FROM test t
WHERE NOT EXISTS (SELECT 1
                  FROM test t2
                  WHERE t2.id = t.id AND
                        (t2.value1 < t.value1 OR
                         (t2.value1 = t.value1 and t2.value2 < t.value2) )
                 );

另一种方法是使用变量:

select t.*
from (select t.*,
             (@rn := if(@i = id, @rn + 1,
                        if(@i := id, 1, 1)
                       )
             ) as rn
      from test t cross join
           (select @rn := 0, @i := -1) params
      order by id, value1, value2
     ) t
where rn = 1;

答案 2 :(得分:0)

考虑以下内容......

DROP TABLE IF EXISTS my_table;

CREATE TABLE my_table
(id INT NOT NULL
,meta1 VARCHAR(12)
,meta2 VARCHAR(12)
,value1 DECIMAL(5,2)
,value2 DECIMAL(5,2)
);

INSERT INTO my_table VALUES
(1 ,'foo','bar',0.1,0.09),
(1 ,'baz','quux',0.2,0.08),
(1 ,'lorem','ipsum',0.1,0.07),
(2 ,'dolor','sit',0.2,0.06),
(2 ,'amet','eos',0.3,0.05),
(3 ,'clita','corpora',0.5,0.04);

SELECT a.*
  FROM my_table a
  JOIN 
     ( SELECT x.id
            , x.value1
            , MIN(x.value2) min_value2  
         FROM my_table x 
         JOIN 
            ( SELECT id
                   , MIN(value1) min_value1 
                FROM my_table 
               GROUP  
                  BY id
            ) y 
           ON y.id = x.id 
          AND y.min_value1 = x.value1
        GROUP 
           BY x.id
            , x.value1
     ) b
    ON b.id = a.id 
   AND b.value1 = a.value1
   AND b.min_value2 = a.value2;

+----+-------+---------+--------+--------+
| id | meta1 | meta2   | value1 | value2 |
+----+-------+---------+--------+--------+
|  1 | lorem | ipsum   |   0.10 |   0.07 |
|  2 | dolor | sit     |   0.20 |   0.06 |
|  3 | clita | corpora |   0.50 |   0.04 |
+----+-------+---------+--------+--------+

你可以无限期地扩展它,但在某些时候,替代解决方案可能变得更容易管理......

DROP TABLE IF EXISTS my_table;

CREATE TABLE my_table
(id INT NOT NULL
,meta1 VARCHAR(12)
,meta2 VARCHAR(12)
,value1 DECIMAL(5,2)
,value2 DECIMAL(5,2)
);

INSERT INTO my_table VALUES
(1 ,'foo'  ,'bar'    ,0.1,0.09),
(1 ,'baz'  ,'quux'   ,0.2,0.08),
(1 ,'lorem','ipsum'  ,0.1,0.07),
(2 ,'dolor','sit'    ,0.2,0.06),
(2 ,'amet' ,'eos'    ,0.3,0.05),
(3 ,'clita','corpora',0.5,0.04),
(1 ,'bar'  ,'foo'    ,0.1,0.07);

SELECT a.*
  FROM my_table a
  JOIN 
     ( 
     SELECT q.id 
          , q.value1
          , q.value2
          , MIN(q.meta1) min_meta1
       FROM my_table q
       JOIN 
          (
             SELECT x.id
                  , x.value1
                  , MIN(x.value2) min_value2  
               FROM my_table x 
               JOIN 
                  ( SELECT id
                         , MIN(value1) min_value1 
                      FROM my_table 
                     GROUP  
                        BY id
                  ) y 
                 ON y.id = x.id 
                AND y.min_value1 = x.value1
              GROUP 
                 BY x.id
                  , x.value1
          ) r
         ON r.id = q.id
        AND r.value1 = q.value1
        AND r.min_value2 = q.value2
      GROUP 
         BY q.id
          , q.value1
          , q.value2
      ) b
    ON b.id = a.id 
   AND b.value1 = a.value1
   AND b.value2 = a.value2
   AND b.min_meta1 = a.meta1;

+----+-------+---------+--------+--------+
| id | meta1 | meta2   | value1 | value2 |
+----+-------+---------+--------+--------+
|  2 | dolor | sit     |   0.20 |   0.06 |
|  3 | clita | corpora |   0.50 |   0.04 |
|  1 | bar   | foo     |   0.10 |   0.07 |
+----+-------+---------+--------+--------+