Давайте предположим, что мы имеем
CREATE TABLE quotes(
`date` date not null primary key,
price numeric(5,1) not null,
valuation integer not null
);
INSERT INTO quotes VALUES
('2016-06-01', 9.2, 9),
('2016-05-31', 9.3, 5),
('2016-05-27', 9.5, 8),
('2016-05-26', 9.7, 7),
('2016-05-25', 9.5, 8),
('2016-05-24', 9.3, 4),
('2016-05-23', 9.2, 3),
('2016-05-20', 9.2, 5),
('2016-05-19', 8.9, 9),
('2016-05-18', 9.1, 4),
('2016-05-17', 9.2, 9);
Тогда следующий SELECT
оператор делает трюк:
SELECT basedate, quotes.*
FROM
(
SELECT basedate, min(date) AS nextDate
FROM
(
SELECT * FROM
(SELECT date as basedate FROM quotes WHERE Valuation > 5) as dates
LEFT JOIN quotes ON dates.basedate < quotes.date
) as aggrtable
GROUP BY basedate
) as fullTable
LEFT JOIN quotes ON fullTable.nextDate = quotes.date;
Давайте проверим это один из внутреннего к внешнему:
- innerst Оператор
SELECT
извлекает цитаты из заинтересованы вообще VALUATION > 5
. Эти даты, где это условие выполняется, называются здесь basedate
.
- Следующий слой соединяет неэквивалент с самой таблицей, определяя все возможные даты «после» наших базовых дат.
- Псевдоним
aggrtable
определяет даты, которые являются «после» базовой даты, но остаются ближе к базовой дате (с использованием функции агрегации min
).
- Чтобы снова получить значения из
quotes
, результат снова соединяется с исходной таблицей, что делает условие соединения «минимальной ближайшей датой» базовой даты.
NB: Это неравновесное соединение между ними может стать уродливым на больших таблицах. Предположим, что в базе данных имеется несколько десятков лет. На второй день оценка прошла выше 5. Тогда это неравновесное объединение будет генерировать все даты в результате, кроме первых двух. Таким образом, если вам не повезло, это может привести к записи O(n²)
, которые необходимо создать временно, но затем снова сгущаются за счет агрегации более min
. Таким образом, ваш результирующий набор будет иметь максимум O(n)
записей, но может потребоваться время O(n²)
. Вы также можете перекрестно проверить это обсуждение, используя инструкцию EXPLAIN
; там вы найдете EXTRA = "Using temporary, Using filesort"
, который является чем-то очень злым в отношении производительности.
Не легко. MySQL не имеет встроенной поддержки функций row-number'ish и других представлений. Есть рабочие места. В любом случае первым шагом является установление плотного упорядочения, затем объединение в prev + next rows (на основе упорядочения), а затем выберите только те объединенные записи, которые удовлетворяют условию. Для более мелких наборов данных зависимый подзапрос * также будет работать соответствующим образом. – user2864740
Спасибо за быстрый ответ. Если бы был добавлен столбец ключа индекса, это поможет? –
Первый/следующий должен быть детерминированным, так что он может быть соединением 'on a.row_rn = b.row_rn + 1' или аналогичным. В зависимом подзапросе это требование отсутствует, так как внутри него можно использовать 'min \ max' с внутренним фильтром' where'. – user2864740