MySQL select 个最接近 MySQL 个结果的子集

MySQL select closest match within a subset of MySQL results

假设我有以下 MySQL (InnoDB) table:

+-------------------------------------------------------------------+
|                          table "taskList"                         |
+----+------------------+----------+---------------------+----------+
| ID | TaskName         | Category | Date_time           | Priority |
+----+------------------+----------+---------------------+----------+
| 1  | cleanup          |   system | 2019-06-02 03:30:00 |        5 |
+----+------------------+----------+---------------------+----------+
| 2  | create_user      |   system | 2019-03-23 11:56:10 |        5 |
+----+------------------+----------+---------------------+----------+
| 3  | send_invoice     |   system | 2019-03-23 11:56:17 |        6 |
+----+------------------+----------+---------------------+----------+
| 4  | perform_selftest |   system | 2019-06-25 06:54:11 |        1 |
+----+------------------+----------+---------------------+----------+
| 5  | add_destination  |      map | 2019-02-15 16:21:04 |        2 |
+----+------------------+----------+---------------------+----------+
| 6  | verify_VIN       |  chassis | 2019-01-04 09:35:49 |        5 |
+----+------------------+----------+---------------------+----------+


我想编写一个查询来选择符合以下所有条件的任何记录(请注意,引号之间的值是示例,将在现实世界中进行参数化):

本例中符合前两个条件的记录有4条。但是在这 4 个中,只有 2 个符合优先级条件。所以这里应该返回记录 #1 和 #2(并且只有那些)。


通过搜索该网站,我编写了以下似乎有效的查询,但它非常丑陋,我觉得它在性能方面可能更有效:

SELECT * FROM taskList
WHERE category='system'
AND (Date_time BETWEEN '2019-01-01' AND '2019-07-01') 
AND Priority=(
   SELECT MIN(Priority) FROM taskList
   WHERE category='system'
   AND (Date_time BETWEEN '2019-01-01' AND '2019-07-01') 
   AND Priority >= 2
)
ORDER BY Date_time DESC

有谁知道更好的方法吗?

未测试,因为未提供 DDL:

SELECT x.columns
     , x.you
     , x.actually
     , x.want
  FROM taskList x
  LEFT
  JOIN tasklist y
    ON y.category = x.category
   AND y.date_time = x.date_time
   AND y.priority < 2
 WHERE x.category='system'
   AND x.date_time BETWEEN '2019-01-01' AND '2019-07-01'
   AND y.id IS NULL;

您的查询使用相关子查询进行过滤,似乎很适合您的用例,并且应该具有相当不错的性能,尤其是在 (category, Date_time, Priority).

上的索引

如果你是运行 MySQL 8.0,你也可以尝试使用rank()。这为您提供了更简洁的查询(您需要将性能与原始查询进行比较):

SELECT *
FROM (
        SELECT 
            t.* ,
            RANK() OVER(PARTITION BY category ORDER BY Priority) rn
        FROM taskList t
        WHERE 
            Category = 'system'
            AND Date_time BETWEEN '2019-01-01' AND '2019-07-01') 
            AND Priority >= 2
) t
WHERE rn = 1

注意:我将 Category 添加到排名分区,以防您需要使查询考虑多个类别。