Коррелированный подзапрос может быть переписан
SELECT dm2.timestamp
FROM dup_mail dm2
WHERE dm2.email = dm1.email
ORDER
BY dm2.has_sales DESC
, dm2.timestamp ASC
LIMIT 1
Это позволит отсортировать строки с has_sales=1
перед строками с has_sales=0
, а затем с timestamp
.Предложение LIMIT 1
выбирает первую строку (после того, как набор отсортирован.)
Нам понадобится подходящий индекс для таблицы dup_mail
с email
в качестве ведущего столбца.Включение в индекс столбцов timestamp
и has_sales
сделает его вспомогательным индексом для подзапроса.
Это должно соответствовать спецификации, но коррелированный подзапрос может не быть оптимальным с точки зрения производительности.
SELECT dm1.uuid
, dm1.email
, dm1.timestamp
, dm1.has_sales
FROM dup_mail dm1
WHERE dm1.timestamp =
( SELECT dm2.timestamp
FROM dup_mail dm2
WHERE dm2.email = dm1.email
ORDER
BY dm2.has_sales DESC
, dm2.timestamp ASC
LIMIT 1
)
ORDER
BY ...
(Немного странно, что отметка времени будет уникальной для всех строк; но если это так, то этот запрос может сработать.)
Мы могли бы получить лучшую производительность с чем-токак это:
SELECT dmx.email
, IF( MAX(dmx.has_sales)=0
, MIN(dmx.timestamp)
, MIN(IF(dmx.has_sales=1,dmx.timestamp,NULL))
) AS min_timestamp
FROM dup_email dmx
GROUP BY dmx.email
И затем использовать это как встроенное представление и присоединиться к таблице dup_mail
, чтобы получить строки, связанные с минимальной отметкой времени
SELECT dm1.uuid
, dm1.email
, dm1.timestamp
, dm1.has_sales
FROM ( -- minimum timestamp for each email
SELECT dmx.email
, IF( MAX(dmx.has_sales)=0
, MIN(dmx.timestamp)
, MIN(IF(dmx.has_sales=1,dmx.timestamp,NULL))
) AS min_timestamp
FROM dup_email dmx
GROUP BY dmx.email
) m
JOIN dup_email dm1
ON dm1.email = m.email
AND dm1.timestamp = m.min_timestamp
ORDER
BY ...
ПРИМЕЧАНИЕ
Синтаксис SQL, приведенный выше, специфичен для MySQL (вопрос помечен как MySQL).
Я думаю, что функция IF()
является расширением только для MySQL.
Для PostgreSQL замените это:
, IF( MAX(dmx.has_sales)=0
, MIN(dmx.timestamp)
, MIN(IF(dmx.has_sales=1,dmx.timestamp,NULL))
) AS min_timestamp
на более переносимый, более совместимый со стандартами ANSI
, CASE WHEN MAX(dmx.has_sales) = 0
THEN MIN(dmx.timestamp)
ELSE MIN( CASE WHEN dmx.has_sales = 1
THEN dmx.timestamp
END
)
END AS min_timestamp