То, что серьезно, не всегда бывает верно (Б. Дизраэли).

Выберите max, min, последнюю строку для каждой группы в SQL без подзапроса

2 мин для чтения
FavoriteLoadingДобавить в избранное
1 Звезда2 Звезды3 Звезды4 Звезды5 Звезд (1 оценок, среднее: 5,00 из 5)
Загрузка...
20 апреля 2019
Язык программирования SQL
В нескольких базах данных СУБД, включая MySQL, подзапросы часто являются одной из причин проблем с производительностью. Поэтому у нас есть стимул избегать их всякий раз, когда мы можем, и находить альтернативные способы реализации наших требований.

Одно из самых популярных применений для подвыборов в SQL – это когда нужно выбрать первую, последнюю, максимальную или минимальную строку для каждой группы в таблице. Например, как бы вы реализовали SQL-запрос, который должен получать сотрудников с максимальной зарплатой для каждого отдела из таблицы сотрудников? На самом деле, получение самой зарплаты довольно просто, но это становится более сложным, когда вы хотите получить имя сотрудника (данные строки) вместе с максимальной зарплатой.

Давайте посмотрим на таблицу:

NameSalaryRole
David130,000Software Engineer
AndreyEx175,000DevOps Engineer
Marina120,000Software Engineer
Anton130,000DevOps Engineer
Alice110,000Software Engineer
Maxim95,000DevOps Engineer

 

Обычной практикой будет написание решения этой проблемы с помощью подбора. Чтобы избежать этой практики, нам нужно перефразировать проблему и углубиться в нее.

Новая проблема:  найти всех сотрудников там, где есть не менее доходный сотрудник той же роли.

Теперь давайте рассмотрим меньшие части этого требования:
Найти всех сотрудников:

select * from employees

 

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

  1. присоединиться к таблице слева, используя поле роли.
  2. добавить условие, чтобы заработная плата была самой высокой.
SELECT
empl1.*, empl2.salary
FROM
employees AS empl1
LEFT OUTER JOIN
employees AS empl2 ON empl2.role = empl1.role
AND empl2.salary > empl1.salary

 

Теперь давайте посмотрим на результат второго шага. Вы заметите, что строки с максимальным окладом содержат запись NULL для объединенного столбца окладов.

NameSalaryRoleSalary (joint)
David130,000Software EngineerNULL
AndreyEx175,000DevOps EngineerNULL
Marina120,000Software Engineer130,000
Anton130,000DevOps Engineer175,000
Alice110,000Software Engineer120,000
Alice110,000Software Engineer130,000
Maxim95,000DevOps Engineer130,000
Maxim95,000DevOps Engineer175,000

 

Поэтому следующим простым шагом будет просто отфильтровать все остальные строки, добавив еще одно условие:

SELECT
empl1.*, empl2.salary
FROM
employees AS empl1
LEFT OUTER JOIN
employees AS empl2 ON empl2.role = empl1.role
AND empl2.salary > empl1.salary
WHERE
empl2.salary IS NULL;

 

И конечный результат:

David130,000Software EngineerNULL
AndreyEx175,000DevOps EngineerNULL

 

Обратите внимание – чтобы это решение работало, вам нужно убедиться, что у вас есть правильный индекс. В этом примере вам нужно будет создать индекс, включающий  столбцы role и  salary, чтобы избежать полного сканирования таблиц.

Если вы нашли ошибку, пожалуйста, выделите фрагмент текста и нажмите Ctrl+Enter.

Просмотров: 63

Если статья понравилась, то поделитесь ей в социальных сетях:

Читайте также

    Добавить комментарий

    Войти с помощью: 

    Ваш e-mail не будет опубликован. Обязательные поля помечены *

    Сообщить об опечатке

    Текст, который будет отправлен нашим редакторам:

    Заполните форму и наш менеджер перезвонит Вам в самое ближайшее время!

    badge
    Обратный звонок 1
    Отправить
    galka

    Спасибо! Ваша заявка принята

    close
    galka

    Спасибо! Ваша заявка принята

    close