MySQL выбирает наиболее близкое соответствие в подмножестве результатов MySQL - PullRequest
0 голосов
/ 09 ноября 2019

Предположим, у меня есть следующая таблица 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 |
+----+------------------+----------+---------------------+----------+

Я хочу написать запрос, выбирая любые записи, которые соответствуют всем следующим условиям (обратите внимание, что значения между кавычками являются примерами и будут параметризованы в реальном мире):

  • Категория '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

Кто-нибудь знает олучший способ сделать это?

Ответы [ 2 ]

1 голос
/ 10 ноября 2019

Не проверено, поскольку не были предоставлены 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;
0 голосов
/ 11 ноября 2019

Ваш запрос, который использует коррелированный подзапрос для фильтрации, кажется, соответствует вашему сценарию использования и должен иметь довольно хорошую производительность, особенно с индексом на (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 в ранг-раздел, на случай, если вам когда-нибудь понадобитсяВ запросе учитывается более одной категории.

...