MySQL查询以查找每组*最佳*行,其中* best *是一个复杂的度量标准

时间:2018-06-12 12:11:28

标签: mysql

我的表格foobar包含以下列:

val: tinyint NOT NULL date: timestamp NOT NULL type: enum('A', 'B', 'C') NOT NULL extra: tinyint NOT NULL

对于每个type,我希望找到与列上的任意条件匹配的行(例如extra > 12 AND val > 0),最小化val,并且在{{1}的情况下{{1}最小化val。我假设对于每个date这样的行存在并且是唯一的。最后,我希望typetype排序结果(与不同的val值一样多的行)。

如果date包含以下行:

foobar

查询应返回:

+------+---------------------+------+-------+
| val  | date                | type | extra |
+------+---------------------+------+-------+
| -1   | 2014-04-10 00:00:00 | A    | 40    |
|  1   | 2014-04-15 00:00:00 | A    | 15    |
|  2   | 2014-04-12 00:00:00 | A    | 77    |
|  1   | 2014-04-11 00:00:00 | A    |  2    |
|  1   | 2014-04-14 00:00:00 | A    | 22    |
|  1   | 2014-04-10 00:00:00 | B    | 40    |
|  1   | 2014-04-15 00:00:00 | B    | 15    |
|  1   | 2014-04-12 00:00:00 | B    | 77    |
|  1   | 2014-04-11 00:00:00 | B    |  2    |
|  1   | 2014-04-14 00:00:00 | B    | 22    |
|  4   | 2014-04-10 00:00:00 | C    | 40    |
|  3   | 2014-04-15 00:00:00 | C    | 15    |
|  3   | 2014-04-12 00:00:00 | C    | 77    |
|  1   | 2014-04-11 00:00:00 | C    |  2    |
|  3   | 2014-04-14 00:00:00 | C    | 22    |
+------+---------------------+------+-------+

这似乎有效:

+------+---------------------+------+-------+
| val  | date                | type | extra |
+------+---------------------+------+-------+
|  1   | 2014-04-10 00:00:00 | B    | 40    |
|  1   | 2014-04-14 00:00:00 | A    | 22    |
|  3   | 2014-04-12 00:00:00 | C    | 77    |
+------+---------------------+------+-------+

但我发现它过于复杂,我怀疑必须有更好的方法。此外,在单个数值(SELECT a.* FROM ( SELECT MIN(val * 4294967296 + UNIX_TIMESTAMP(date)) AS score FROM foobar WHERE extra > 12 AND val > 0 GROUP BY type ) AS b INNER JOIN foobar AS a ON a.val * 4294967296 + UNIX_TIMESTAMP(a.date) = b.score ORDER BY val, date; )中转换我的多列标准适用于这种简单的情况,但在更复杂的情况下可能更难。

是否有其他更通用的方案可以做同样的事情?

1 个答案:

答案 0 :(得分:1)

DROP TABLE IF EXISTS my_table;

CREATE TABLE my_table
(val INT SIGNED NOT NULL
,date TIMESTAMP NOT NULL
,type CHAR(1) NOT NULL 
,extra TINYINT NOT NULL
,PRIMARY KEY(val,date,type)
);

INSERT INTO my_table VALUES
(-1,'2014-04-10 00:00:00','A',40),
( 1,'2014-04-15 00:00:00','A',15),
( 2,'2014-04-12 00:00:00','A',77),
( 1,'2014-04-11 00:00:00','A', 2),
( 1,'2014-04-14 00:00:00','A',22),
( 1,'2014-04-10 00:00:00','B',40),
( 1,'2014-04-15 00:00:00','B',15),
( 1,'2014-04-12 00:00:00','B',77),
( 1,'2014-04-11 00:00:00','B', 2),
( 1,'2014-04-14 00:00:00','B',22),
( 4,'2014-04-10 00:00:00','C',40),
( 3,'2014-04-15 00:00:00','C',15),
( 3,'2014-04-12 00:00:00','C',77),
( 1,'2014-04-11 00:00:00','C', 2),
( 3,'2014-04-14 00:00:00','C',22);

SELECT a.* 
  FROM my_table a 
  JOIN 
     ( SELECT x.val
            , x.type
            , MIN(x.date) date 
         FROM my_table x 
         JOIN 
            ( SELECT MIN(val) val
                   , type
                FROM my_table 
               WHERE extra > 12 
                 AND val > 0 
               GROUP 
                  BY type
            ) y 
           ON y.type = x.type 
          AND y.val = x.val 
        WHERE x.extra > 12
        GROUP 
           BY val
            , type
     ) b 
    ON b.val = a.val 
   AND b.type = a.type 
   AND b.date = a.date;

+-----+---------------------+------+-------+
| val | date                | type | extra |
+-----+---------------------+------+-------+
|   1 | 2014-04-14 00:00:00 | A    |    22 |
|   1 | 2014-04-10 00:00:00 | B    |    40 |
|   3 | 2014-04-12 00:00:00 | C    |    77 |
+-----+---------------------+------+-------+