MySQL在MySQL结果的子集中选择最接近的匹配

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

+-------------------------------------------------------------------+
|                          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 |
+----+------------------+----------+---------------------+----------+


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

  • 类别“系统”
  • “ 2019-01-01”到“ 2019-07-01”之间的日期时间
  • 此子集中的优先级最高,最接近“ 2”(允许2本身,但不允许更高,例如1)

在这种情况下,有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

有人知道更好的方法吗?

ap0705122 回答:MySQL在MySQL结果的子集中选择最接近的匹配

未经测试,因为未提供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添加到等级分区中,以防您需要使查询考虑多个类别。

本文链接:https://www.f2er.com/3132849.html

大家都在问