#mysql #sql
#mysql #sql
Вопрос:
Предположим, у меня есть клиент с большим количеством платежей. Как мне запросить, чтобы получить всех клиентов, у которых нет записей о платежах за последние 90 дней?
clients
=======
id integer
name string
payments
========
id integer
client_id integer
created_at datetime
По сути, обратное:
select *
from clients
inner join payments on payments.client_id = clients.id
where payments.created_at > utc_timestamp() - interval 90 day
Надеюсь, более эффективный, чем:
select *
from clients
where id not in (
select *
from clients
inner join payments on payments.client_id = clients.id
where payments.created_at > utc_timestamp() - interval 90 day
)
Комментарии:
1. Последний запрос выполняется медленно или что-то в этомроде?
2. Какой диалект SQL вы используете?
3. @Oded: mysql; @Abe: еще не пробовал в производстве, но могу прибегнуть к нему, если понадобится
Ответ №1:
Убедитесь, что есть индекс на payments(client_id)
, или даже лучше, payments(client_id, created_at
).
Для альтернативного способа написания вашего запроса вы могли бы попробовать not exists
, например:
select *
from clients c
where not exists
(
select *
from payments p
where p.payments.client_id = clients.id
and payments.created_at > utc_timestamp() - interval 90 day
)
Или эксклюзивное левое соединение:
select *
from clients c
left join
payments p
on p.payments.client_id = clients.id
and payments.created_at > utc_timestamp() - interval 90 day
where p.client_id is null
Если оба работают медленно, добавьте explain extended
выходные данные к вашему вопросу, чтобы мы могли понять, почему.
Комментарии:
1. Спасибо, эксклюзивное левое соединение, похоже, является правильным решением.
Ответ №2:
select *
from clients
left join payments on
payments.client_id = clients.id and
payments.created_at > utc_timestamp() - interval 90 day
where payments.client_id is null