MySQL группировка и сортировка - PullRequest
2 голосов
/ 30 января 2020
mysql> describe jobs;
+--------------+---------+------+-----+---------+----------------+
| Field        | Type    | Null | Key | Default | Extra          |
+--------------+---------+------+-----+---------+----------------+
| job_id       | int(11) | NO   | PRI | NULL    | auto_increment |
| candidate_id | int(11) | NO   | MUL | NULL    |                |
| company_id   | int(11) | NO   | MUL | NULL    |                |
| start_date   | date    | NO   | MUL | NULL    |                |
| end_date     | date    | NO   | MUL | NULL    |                |
+--------------+---------+------+-----+---------+----------------+
5 rows in set (0.01 sec)

Каждый кандидат может иметь несколько заданий. Я хочу найти последнюю работу для каждого кандидата (на основе даты начала, потому что датой окончания может быть 0000-00-00), и проверить (в PHP), если end_Date не является 0000-00-00.

(если ваша последняя дата окончания не 0000-00-00, значит, вы сейчас безработный, и это то, что я ищу; я не знаю, как это сделать в моем запросе, поэтому сделаю это в PHP).

Запрос SELECT candidate_id, end_Date FROM jobs ORDER BY candidate_id , start_date DESC ставит меня на полпути.

+--------------+------------+
| candidate_id | end_Date   |
+--------------+------------+
|            1 | 2019-08-31 |
|            1 | 2019-01-31 |
|            1 | 2019-05-31 |
|            2 | 0000-00-00 |
|            2 | 2018-02-28 |
|            2 | 2017-05-31 |
|            2 | 2016-09-30 |
|            3 | 0000-00-00 |
|            3 | 2019-05-31 |
|            4 | 2019-04-30 |
|            4 | 2019-09-30 |

(Как) я могу получить только первую запись (строку с самой последней start_date) для Идентификатор каждого кандидата? И можно ли получить только те, в которых дата окончания не зарегистрирована в 0000-00-00?

(Ой, похоже, мой порядок по end_date не работает)

Ответы [ 4 ]

2 голосов
/ 30 января 2020

Можно выполнить фильтрацию с помощью коррелированного подзапроса:

select j.*
from jobs j
where j.start_date = (
    select max(start_date)
    from jobs j1
    where j1.candidate_id = j.candidate_id and j1.end_date <> '0000-00-00'
)

Подзапрос возвращает наибольшее значение start_date, для которого end_date не равно null для текущего кандидата.

Другой типичный Чтобы решить эту первую проблему для каждой группы, нужно использовать соединение anti с левым выходом:

select j.*
from jobs j
left join jobs j1 
    on  j1.candidate_id = j.candidate_id
    and j1.start_date > j.start_date
    and j1.end_date is not null
where 
    j.end_date is not null
    and j1.job_id is null

Это выражается следующим образом: дайте мне записи с ненулевым числом null end_date, для которого нет существует другая запись с тем же candidate_id, большим start_date и не-null end_date.

1 голос
/ 30 января 2020

Опция без подзапроса:

SELECT
    j.*
FROM
    jobs AS j
    LEFT JOIN jobs AS j2 ON (
            j2.candidate_id = j.candidate_id
        AND j2.start_date   > j.start.date
    )
WHERE
    j2.candidate_id IS NULL

Вы хотели бы иметь составной индекс (андидат_идентификатор_старта) для оптимизации запроса.

1 голос
/ 30 января 2020

Вы можете использовать соединение в группе max start_date по кандидатам

select  * 
from jobs j
inner join  (

  select candidate_id ,  max(start_date) max_start_date 
  from jobs
  group by   candidate_id

  ) t on t.candidate_id = j.candidate_id 
    and t.max_start_date = j.start_date 
0 голосов
/ 31 января 2020

Вы можете сделать это с агрегацией:

select candidate_id,
       (case when sum(end_date = '0000-00-00') > 0
             then '0000-00-00'
             else max(end_date)
        end) as enddate
from jobs j
group by candidate_id;

Или другим способом:

select j.*
from jobs j
where j.end_date = '0000-00-00' or
      (not exists (select 1
                   from jobs j2
                   where j2.candidate_id = j.candidate_id and
                         (j2.end_date = '0000-00-00' or
                          j2.end_date > j.end_date
                         )
                  )
      );

Или даже:

select j.*
from jobs j
where j.job_id = (select j2.job_id
                  from jobs j2
                  where j2.candidate_id = j.candidate_id
                  order by (j2.end_date = '0000-00-00') desc,
                           j2.end_date desc
                 );
...