MySQL находит базу первой строки по нескольким условиям

#mysql #sql

Вопрос:

Предположим, существует следующая таблица:

 id    B     C     D
1     2     3     4
1     2     4     3
2     1     2     4
2     3     1     5
 

Для каждого идентификатора я хочу сохранить строку с максимальным значением B, если B равно, то сохраните строку с максимальным значением C. Таким образом, конечный результат таков,

 id    B     C     D
1     2     4     3
2     3     1     5
 

как это реализовать с помощью SQL?

Комментарии:

1. какую версию mysql вы используете ?

2. mysql версии 5.6

3. Обязательно ли вам работать с такой старой версией? Вы не можете обновить? Такие задачи гораздо проще решаются с MySQL 8.

4. Версия не может быть изменена бизнес-командой, поскольку управление БД находится на уровне предприятия.

Ответ №1:

Максимальные задачи могут быть решены с NOT EXISTS помощью . Вам нужны только строки, для которых не существует строки с тем же идентификатором и большим B или с тем же B и более высоким C.

 select *
from mytable t1
where not exists
(
  select null
  from mytable t2
  where t2.id = t1.id
  and 
  (
    t2.b > t1.b
    or
    (t2.b = t1.b and t2.c > t1.c)
  )
);
 

Начиная с MyQL 8 , мы можем просто ранжировать наши строки с RANK DENSE_RANK помощью или ROW_NUMBER вместо этого:

 select id, b, c, d
from
(
  select id, b, c, d, row_number() over (partition by id order by b desc, c desc) as rn
  from mytable
) t
where rn = 1;
 

Демо: https://dbfiddle.uk/?rdbms=mysql_8.0amp;fiddle=a54a906373e0dd00a2fb42c119186dd3

Ответ №2:

Поскольку вы используете 5.6, поэтому функция ранга там работать не будет. Попробуйте следующий подход

 select id, B, C, D
FROM
(
  select id, B, C, D,
    @order_id := IF(@current_id = id,
    @order_id   1, 1) AS order_id,
    @current_id := id
  from Test 
  order by  id asc, B desc, C DESC
) T WHERE order_id=1
 

Ответ №3:

Подходы Торстена прекрасны. Другой метод заключается в использовании кортежей для сопоставления строк:

 select t.*
from t
where (t.b, t.c) = (select t2.b, t2.c
                    from t t2
                    where t2.id = t.id
                    order by t2.b desc, t2.c desc
                    limit 1
                   );