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 |
+----+------------------+----------+---------------------+----------+
我想编写一个查询来选择符合以下所有条件的任何记录(请注意,引号之间的值是示例,将在现实世界中进行参数化):
- 类别'system'
- Date_time 在“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
有谁知道更好的方法吗?
未测试,因为未提供 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
添加到排名分区,以防您需要使查询考虑多个类别。
假设我有以下 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 |
+----+------------------+----------+---------------------+----------+
我想编写一个查询来选择符合以下所有条件的任何记录(请注意,引号之间的值是示例,将在现实世界中进行参数化):
- 类别'system'
- Date_time 在“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
有谁知道更好的方法吗?
未测试,因为未提供 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
添加到排名分区,以防您需要使查询考虑多个类别。